aboutsummaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/common/tuners/Kconfig9
-rw-r--r--drivers/media/common/tuners/Makefile5
-rw-r--r--drivers/media/common/tuners/max2165.c48
-rw-r--r--drivers/media/common/tuners/mc44s803.c10
-rw-r--r--drivers/media/common/tuners/mt2060.c13
-rw-r--r--drivers/media/common/tuners/mt2060_priv.h1
-rw-r--r--drivers/media/common/tuners/mt2063.c2307
-rw-r--r--drivers/media/common/tuners/mt2063.h32
-rw-r--r--drivers/media/common/tuners/mt2131.c20
-rw-r--r--drivers/media/common/tuners/mt2131_priv.h1
-rw-r--r--drivers/media/common/tuners/mt2266.c25
-rw-r--r--drivers/media/common/tuners/mxl5005s.c69
-rw-r--r--drivers/media/common/tuners/mxl5007t.c98
-rw-r--r--drivers/media/common/tuners/qt1010.c21
-rw-r--r--drivers/media/common/tuners/qt1010_priv.h1
-rw-r--r--drivers/media/common/tuners/tda18212.c72
-rw-r--r--drivers/media/common/tuners/tda18212.h4
-rw-r--r--drivers/media/common/tuners/tda18218.c34
-rw-r--r--drivers/media/common/tuners/tda18218_priv.h2
-rw-r--r--drivers/media/common/tuners/tda18271-fe.c83
-rw-r--r--drivers/media/common/tuners/tda18271-maps.c4
-rw-r--r--drivers/media/common/tuners/tda18271-priv.h2
-rw-r--r--drivers/media/common/tuners/tda18271.h1
-rw-r--r--drivers/media/common/tuners/tda827x.c52
-rw-r--r--drivers/media/common/tuners/tuner-simple.c68
-rw-r--r--drivers/media/common/tuners/tuner-types.c4
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.c143
-rw-r--r--drivers/media/common/tuners/xc4000.c191
-rw-r--r--drivers/media/common/tuners/xc5000.c194
-rw-r--r--drivers/media/common/tuners/xc5000.h5
-rw-r--r--drivers/media/dvb/b2c2/flexcop.c29
-rw-r--r--drivers/media/dvb/bt8xx/dst.c72
-rw-r--r--drivers/media/dvb/bt8xx/dst_common.h2
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c205
-rw-r--r--drivers/media/dvb/ddbridge/ddbridge-core.c3
-rw-r--r--drivers/media/dvb/ddbridge/ddbridge.h2
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c7
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c1
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c934
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h27
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c4
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig24
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile14
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-fe.c105
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.c25
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.h2
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c541
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.h8
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.c446
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.h6
-rw-r--r--drivers/media/dvb/dvb-usb/az6007.c957
-rw-r--r--drivers/media/dvb/dvb-usb/cinergyT2-fe.c34
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c11
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h2
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c11
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c867
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u-fe.c33
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-dvb.c8
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h14
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c93
-rw-r--r--drivers/media/dvb/dvb-usb/friio-fe.c29
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk-fe.c24
-rw-r--r--drivers/media/dvb/dvb-usb/it913x.c506
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.c291
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.h1
-rw-r--r--drivers/media/dvb/dvb-usb/mxl111sf-demod.c42
-rw-r--r--drivers/media/dvb/dvb-usb/mxl111sf-tuner.c102
-rw-r--r--drivers/media/dvb/dvb-usb/mxl111sf.c22
-rw-r--r--drivers/media/dvb/dvb-usb/rtl28xxu.c982
-rw-r--r--drivers/media/dvb/dvb-usb/rtl28xxu.h264
-rw-r--r--drivers/media/dvb/dvb-usb/ttusb2.c19
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x-fe.c20
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045-fe.c32
-rw-r--r--drivers/media/dvb/firewire/firedtv-avc.c98
-rw-r--r--drivers/media/dvb/firewire/firedtv-dvb.c5
-rw-r--r--drivers/media/dvb/firewire/firedtv-fe.c35
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c1
-rw-r--r--drivers/media/dvb/firewire/firedtv.h4
-rw-r--r--drivers/media/dvb/frontends/Kconfig22
-rw-r--r--drivers/media/dvb/frontends/Makefile7
-rw-r--r--drivers/media/dvb/frontends/af9013.c1727
-rw-r--r--drivers/media/dvb/frontends/af9013.h113
-rw-r--r--drivers/media/dvb/frontends/af9013_priv.h93
-rw-r--r--drivers/media/dvb/frontends/atbm8830.c27
-rw-r--r--drivers/media/dvb/frontends/au8522_decoder.c13
-rw-r--r--drivers/media/dvb/frontends/au8522_dig.c66
-rw-r--r--drivers/media/dvb/frontends/bcm3510.c18
-rw-r--r--drivers/media/dvb/frontends/bsbe1.h7
-rw-r--r--drivers/media/dvb/frontends/bsru6.h9
-rw-r--r--drivers/media/dvb/frontends/cx22700.c51
-rw-r--r--drivers/media/dvb/frontends/cx22702.c91
-rw-r--r--drivers/media/dvb/frontends/cx24110.c20
-rw-r--r--drivers/media/dvb/frontends/cx24113.c10
-rw-r--r--drivers/media/dvb/frontends/cx24116.c36
-rw-r--r--drivers/media/dvb/frontends/cx24123.c56
-rw-r--r--drivers/media/dvb/frontends/cxd2820r.h19
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_c.c25
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_core.c653
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_priv.h23
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_t.c63
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_t2.c70
-rw-r--r--drivers/media/dvb/frontends/dib0070.c10
-rw-r--r--drivers/media/dvb/frontends/dib0090.c167
-rw-r--r--drivers/media/dvb/frontends/dib0090.h54
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c113
-rw-r--r--drivers/media/dvb/frontends/dib3000mb_priv.h2
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c132
-rw-r--r--drivers/media/dvb/frontends/dib7000m.c136
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c456
-rw-r--r--drivers/media/dvb/frontends/dib7000p.h16
-rw-r--r--drivers/media/dvb/frontends/dib8000.c1073
-rw-r--r--drivers/media/dvb/frontends/dib8000.h42
-rw-r--r--drivers/media/dvb/frontends/dib9000.c157
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.h17
-rw-r--r--drivers/media/dvb/frontends/drxd.h2
-rw-r--r--drivers/media/dvb/frontends/drxd_hard.c68
-rw-r--r--drivers/media/dvb/frontends/drxk.h30
-rw-r--r--drivers/media/dvb/frontends/drxk_hard.c353
-rw-r--r--drivers/media/dvb/frontends/drxk_hard.h9
-rw-r--r--drivers/media/dvb/frontends/ds3000.c38
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c65
-rw-r--r--drivers/media/dvb/frontends/dvb_dummy_fe.c18
-rw-r--r--drivers/media/dvb/frontends/ec100.c20
-rw-r--r--drivers/media/dvb/frontends/hd29l2.c861
-rw-r--r--drivers/media/dvb/frontends/hd29l2.h66
-rw-r--r--drivers/media/dvb/frontends/hd29l2_priv.h314
-rw-r--r--drivers/media/dvb/frontends/it913x-fe-priv.h811
-rw-r--r--drivers/media/dvb/frontends/it913x-fe.c378
-rw-r--r--drivers/media/dvb/frontends/it913x-fe.h47
-rw-r--r--drivers/media/dvb/frontends/itd1000.c7
-rw-r--r--drivers/media/dvb/frontends/ix2505v.c8
-rw-r--r--drivers/media/dvb/frontends/l64781.c117
-rw-r--r--drivers/media/dvb/frontends/lgdt3305.c98
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c43
-rw-r--r--drivers/media/dvb/frontends/lgs8gl5.c29
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.c26
-rw-r--r--drivers/media/dvb/frontends/m88rs2000.c904
-rw-r--r--drivers/media/dvb/frontends/m88rs2000.h66
-rw-r--r--drivers/media/dvb/frontends/mb86a16.c8
-rw-r--r--drivers/media/dvb/frontends/mb86a20s.c546
-rw-r--r--drivers/media/dvb/frontends/mt312.c37
-rw-r--r--drivers/media/dvb/frontends/mt352.c65
-rw-r--r--drivers/media/dvb/frontends/nxt200x.c17
-rw-r--r--drivers/media/dvb/frontends/nxt6000.c32
-rw-r--r--drivers/media/dvb/frontends/or51132.c52
-rw-r--r--drivers/media/dvb/frontends/or51211.c13
-rw-r--r--drivers/media/dvb/frontends/rtl2830.c562
-rw-r--r--drivers/media/dvb/frontends/rtl2830.h97
-rw-r--r--drivers/media/dvb/frontends/rtl2830_priv.h57
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c48
-rw-r--r--drivers/media/dvb/frontends/s5h1411.c48
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c71
-rw-r--r--drivers/media/dvb/frontends/s5h1432.c36
-rw-r--r--drivers/media/dvb/frontends/s921.c23
-rw-r--r--drivers/media/dvb/frontends/si21xx.c20
-rw-r--r--drivers/media/dvb/frontends/sp8870.c29
-rw-r--r--drivers/media/dvb/frontends/sp887x.c50
-rw-r--r--drivers/media/dvb/frontends/stb0899_drv.c49
-rw-r--r--drivers/media/dvb/frontends/stb6000.c8
-rw-r--r--drivers/media/dvb/frontends/stb6100.c6
-rw-r--r--drivers/media/dvb/frontends/stv0288.c19
-rw-r--r--drivers/media/dvb/frontends/stv0297.c37
-rw-r--r--drivers/media/dvb/frontends/stv0299.c32
-rw-r--r--drivers/media/dvb/frontends/stv0367.c156
-rw-r--r--drivers/media/dvb/frontends/stv0900_core.c37
-rw-r--r--drivers/media/dvb/frontends/stv090x.c13
-rw-r--r--drivers/media/dvb/frontends/stv6110.c3
-rw-r--r--drivers/media/dvb/frontends/tda10021.c111
-rw-r--r--drivers/media/dvb/frontends/tda10023.c103
-rw-r--r--drivers/media/dvb/frontends/tda10048.c83
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c115
-rw-r--r--drivers/media/dvb/frontends/tda10071.c8
-rw-r--r--drivers/media/dvb/frontends/tda10086.c62
-rw-r--r--drivers/media/dvb/frontends/tda18271c2dd.c53
-rw-r--r--drivers/media/dvb/frontends/tda8083.c19
-rw-r--r--drivers/media/dvb/frontends/tda826x.c7
-rw-r--r--drivers/media/dvb/frontends/tdhd1.h11
-rw-r--r--drivers/media/dvb/frontends/tua6100.c31
-rw-r--r--drivers/media/dvb/frontends/ves1820.c23
-rw-r--r--drivers/media/dvb/frontends/ves1x93.c23
-rw-r--r--drivers/media/dvb/frontends/zl10036.c10
-rw-r--r--drivers/media/dvb/frontends/zl10039.c10
-rw-r--r--drivers/media/dvb/frontends/zl10353.c116
-rw-r--r--drivers/media/dvb/mantis/mantis_hif.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1033.c8
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2033.c9
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2040.c9
-rw-r--r--drivers/media/dvb/ngene/ngene-cards.c3
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c6
-rw-r--r--drivers/media/dvb/pt1/pt1.c93
-rw-r--r--drivers/media/dvb/pt1/va1j5jf8007s.c6
-rw-r--r--drivers/media/dvb/pt1/va1j5jf8007t.c6
-rw-r--r--drivers/media/dvb/siano/smsdvb.c152
-rw-r--r--drivers/media/dvb/ttpci/av7110.c103
-rw-r--r--drivers/media/dvb/ttpci/av7110.h3
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c50
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c51
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c27
-rw-r--r--drivers/media/dvb/ttpci/budget.c68
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c102
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusbdecfe.c14
-rw-r--r--drivers/media/media-device.c3
-rw-r--r--drivers/media/media-devnode.c3
-rw-r--r--drivers/media/radio/Kconfig418
-rw-r--r--drivers/media/radio/Makefile2
-rw-r--r--drivers/media/radio/radio-aimslab.c440
-rw-r--r--drivers/media/radio/radio-aztech.c372
-rw-r--r--drivers/media/radio/radio-gemtek.c494
-rw-r--r--drivers/media/radio/radio-isa.c340
-rw-r--r--drivers/media/radio/radio-isa.h105
-rw-r--r--drivers/media/radio/radio-keene.c427
-rw-r--r--drivers/media/radio/radio-maxiradio.c379
-rw-r--r--drivers/media/radio/radio-miropcm20.c2
-rw-r--r--drivers/media/radio/radio-rtrack2.c332
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c63
-rw-r--r--drivers/media/radio/radio-si4713.c15
-rw-r--r--drivers/media/radio/radio-tea5764.c19
-rw-r--r--drivers/media/radio/radio-terratec.c365
-rw-r--r--drivers/media/radio/radio-timb.c15
-rw-r--r--drivers/media/radio/radio-trust.c388
-rw-r--r--drivers/media/radio/radio-typhoon.c366
-rw-r--r--drivers/media/radio/radio-wl1273.c17
-rw-r--r--drivers/media/radio/radio-zoltrix.c442
-rw-r--r--drivers/media/radio/saa7706h.c13
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c28
-rw-r--r--drivers/media/radio/si4713-i2c.c15
-rw-r--r--drivers/media/radio/tef6862.c22
-rw-r--r--drivers/media/radio/wl128x/Kconfig4
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c58
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.h28
-rw-r--r--drivers/media/radio/wl128x/fmdrv_rx.c84
-rw-r--r--drivers/media/radio/wl128x/fmdrv_rx.h50
-rw-r--r--drivers/media/radio/wl128x/fmdrv_tx.c61
-rw-r--r--drivers/media/radio/wl128x/fmdrv_tx.h20
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c1
-rw-r--r--drivers/media/rc/Kconfig19
-rw-r--r--drivers/media/rc/Makefile2
-rw-r--r--drivers/media/rc/fintek-cir.c26
-rw-r--r--drivers/media/rc/fintek-cir.h4
-rw-r--r--drivers/media/rc/gpio-ir-recv.c205
-rw-r--r--drivers/media/rc/imon.c26
-rw-r--r--drivers/media/rc/ir-nec-decoder.c4
-rw-r--r--drivers/media/rc/ir-raw.c1
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c67
-rw-r--r--drivers/media/rc/ir-sanyo-decoder.c205
-rw-r--r--drivers/media/rc/ir-sony-decoder.c2
-rw-r--r--drivers/media/rc/keymaps/Makefile3
-rw-r--r--drivers/media/rc/keymaps/rc-hauppauge.c51
-rw-r--r--drivers/media/rc/keymaps/rc-it913x-v1.c95
-rw-r--r--drivers/media/rc/keymaps/rc-it913x-v2.c94
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-pc150u.c102
-rw-r--r--drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c52
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-m1f.c24
-rw-r--r--drivers/media/rc/lirc_dev.c2
-rw-r--r--drivers/media/rc/mceusb.c6
-rw-r--r--drivers/media/rc/rc-core-priv.h14
-rw-r--r--drivers/media/rc/rc-main.c10
-rw-r--r--drivers/media/rc/redrat3.c52
-rw-r--r--drivers/media/rc/streamzap.c4
-rw-r--r--drivers/media/rc/winbond-cir.c4
-rw-r--r--drivers/media/video/Kconfig476
-rw-r--r--drivers/media/video/Makefile28
-rw-r--r--drivers/media/video/adp1653.c20
-rw-r--r--drivers/media/video/adv7170.c75
-rw-r--r--drivers/media/video/adv7175.c13
-rw-r--r--drivers/media/video/adv7180.c14
-rw-r--r--drivers/media/video/adv7183.c699
-rw-r--r--drivers/media/video/adv7183_regs.h107
-rw-r--r--drivers/media/video/adv7343.c13
-rw-r--r--drivers/media/video/ak881x.c13
-rw-r--r--drivers/media/video/aptina-pll.c174
-rw-r--r--drivers/media/video/aptina-pll.h56
-rw-r--r--drivers/media/video/as3645a.c888
-rw-r--r--drivers/media/video/atmel-isi.c49
-rw-r--r--drivers/media/video/au0828/Kconfig1
-rw-r--r--drivers/media/video/au0828/au0828-i2c.c2
-rw-r--r--drivers/media/video/blackfin/Kconfig10
-rw-r--r--drivers/media/video/blackfin/Makefile2
-rw-r--r--drivers/media/video/blackfin/bfin_capture.c1059
-rw-r--r--drivers/media/video/blackfin/ppi.c271
-rw-r--r--drivers/media/video/bt819.c13
-rw-r--r--drivers/media/video/bt856.c13
-rw-r--r--drivers/media/video/bt866.c13
-rw-r--r--drivers/media/video/bt8xx/bt848.h5
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c58
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c5
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c2
-rw-r--r--drivers/media/video/bt8xx/bttv.h3
-rw-r--r--drivers/media/video/c-qcam.c2
-rw-r--r--drivers/media/video/cs5345.c15
-rw-r--r--drivers/media/video/cs53l32a.c15
-rw-r--r--drivers/media/video/cx18/cx18-alsa-main.c1
-rw-r--r--drivers/media/video/cx18/cx18-driver.c6
-rw-r--r--drivers/media/video/cx18/cx18-driver.h2
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c41
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c2
-rw-r--r--drivers/media/video/cx18/cx18-i2c.h2
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c4
-rw-r--r--drivers/media/video/cx231xx/Kconfig6
-rw-r--r--drivers/media/video/cx231xx/cx231xx-417.c1
-rw-r--r--drivers/media/video/cx231xx/cx231xx-audio.c24
-rw-r--r--drivers/media/video/cx231xx/cx231xx-cards.c85
-rw-r--r--drivers/media/video/cx231xx/cx231xx-core.c7
-rw-r--r--drivers/media/video/cx231xx/cx231xx-dvb.c4
-rw-r--r--drivers/media/video/cx231xx/cx231xx-input.c11
-rw-r--r--drivers/media/video/cx231xx/cx231xx-vbi.c4
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c20
-rw-r--r--drivers/media/video/cx231xx/cx231xx.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c141
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c79
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c24
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c113
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c176
-rw-r--r--drivers/media/video/cx23885/cx23885.h14
-rw-r--r--drivers/media/video/cx25821/cx25821-alsa.c75
-rw-r--r--drivers/media/video/cx25821/cx25821-audio-upstream.c113
-rw-r--r--drivers/media/video/cx25821/cx25821-audio.h39
-rw-r--r--drivers/media/video/cx25821/cx25821-cards.c2
-rw-r--r--drivers/media/video/cx25821/cx25821-core.c66
-rw-r--r--drivers/media/video/cx25821/cx25821-i2c.c12
-rw-r--r--drivers/media/video/cx25821/cx25821-medusa-defines.h6
-rw-r--r--drivers/media/video/cx25821/cx25821-medusa-reg.h518
-rw-r--r--drivers/media/video/cx25821/cx25821-medusa-video.c410
-rw-r--r--drivers/media/video/cx25821/cx25821-video-upstream-ch2.c138
-rw-r--r--drivers/media/video/cx25821/cx25821-video-upstream.c156
-rw-r--r--drivers/media/video/cx25821/cx25821-video.c145
-rw-r--r--drivers/media/video/cx25821/cx25821.h4
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c10
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c3254
-rw-r--r--drivers/media/video/cx88/Kconfig10
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c2
-rw-r--r--drivers/media/video/cx88/cx88-cards.c118
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c30
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c2
-rw-r--r--drivers/media/video/cx88/cx88-input.c4
-rw-r--r--drivers/media/video/cx88/cx88.h2
-rw-r--r--drivers/media/video/davinci/dm355_ccdc.c15
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc.c13
-rw-r--r--drivers/media/video/davinci/isif.c14
-rw-r--r--drivers/media/video/davinci/vpbe.c76
-rw-r--r--drivers/media/video/davinci/vpbe_display.c43
-rw-r--r--drivers/media/video/davinci/vpbe_osd.c492
-rw-r--r--drivers/media/video/davinci/vpbe_venc.c224
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c18
-rw-r--r--drivers/media/video/davinci/vpif.h2
-rw-r--r--drivers/media/video/davinci/vpif_capture.c14
-rw-r--r--drivers/media/video/davinci/vpif_display.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c368
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c204
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c285
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c8
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c7
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h5
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c24
-rw-r--r--drivers/media/video/em28xx/em28xx.h37
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c4
-rw-r--r--drivers/media/video/fsl-viu.c13
-rw-r--r--drivers/media/video/gspca/Kconfig10
-rw-r--r--drivers/media/video/gspca/Makefile2
-rw-r--r--drivers/media/video/gspca/benq.c7
-rw-r--r--drivers/media/video/gspca/gl860/Makefile2
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c1
-rw-r--r--drivers/media/video/gspca/gspca.c73
-rw-r--r--drivers/media/video/gspca/gspca.h5
-rw-r--r--drivers/media/video/gspca/jl2005bcd.c554
-rw-r--r--drivers/media/video/gspca/konica.c3
-rw-r--r--drivers/media/video/gspca/m5602/Makefile2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c4
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov7660.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.h2
-rw-r--r--drivers/media/video/gspca/mars.c1
-rw-r--r--drivers/media/video/gspca/nw80x.c2
-rw-r--r--drivers/media/video/gspca/ov519.c5
-rw-r--r--drivers/media/video/gspca/ov534_9.c184
-rw-r--r--drivers/media/video/gspca/pac207.c10
-rw-r--r--drivers/media/video/gspca/pac7302.c584
-rw-r--r--drivers/media/video/gspca/se401.c10
-rw-r--r--drivers/media/video/gspca/sn9c20x.c1176
-rw-r--r--drivers/media/video/gspca/sonixb.c15
-rw-r--r--drivers/media/video/gspca/sonixj.c203
-rw-r--r--drivers/media/video/gspca/spca561.c2
-rw-r--r--drivers/media/video/gspca/stv06xx/Makefile2
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c8
-rw-r--r--drivers/media/video/gspca/t613.c25
-rw-r--r--drivers/media/video/gspca/topro.c2
-rw-r--r--drivers/media/video/gspca/vicam.c3
-rw-r--r--drivers/media/video/gspca/xirlink_cit.c6
-rw-r--r--drivers/media/video/gspca/zc3xx.c443
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c20
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c46
-rw-r--r--drivers/media/video/hdpvr/hdpvr.h1
-rw-r--r--drivers/media/video/imx074.c13
-rw-r--r--drivers/media/video/indycam.c13
-rw-r--r--drivers/media/video/ir-kbd-i2c.c42
-rw-r--r--drivers/media/video/ivtv/Makefile8
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.c62
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c44
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h16
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c120
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c210
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c22
-rw-r--r--drivers/media/video/ivtv/ivtv-udma.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c22
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c4
-rw-r--r--drivers/media/video/ks0127.c13
-rw-r--r--drivers/media/video/m52790.c13
-rw-r--r--drivers/media/video/m5mols/m5mols.h46
-rw-r--r--drivers/media/video/m5mols/m5mols_capture.c83
-rw-r--r--drivers/media/video/m5mols/m5mols_core.c303
-rw-r--r--drivers/media/video/m5mols/m5mols_reg.h247
-rw-r--r--drivers/media/video/marvell-ccic/mcam-core.c77
-rw-r--r--drivers/media/video/marvell-ccic/mcam-core.h1
-rw-r--r--drivers/media/video/marvell-ccic/mmp-driver.c46
-rw-r--r--drivers/media/video/msp3400-driver.c19
-rw-r--r--drivers/media/video/msp3400-driver.h6
-rw-r--r--drivers/media/video/mt9m001.c18
-rw-r--r--drivers/media/video/mt9m032.c868
-rw-r--r--drivers/media/video/mt9m111.c393
-rw-r--r--drivers/media/video/mt9p031.c85
-rw-r--r--drivers/media/video/mt9t001.c18
-rw-r--r--drivers/media/video/mt9t031.c18
-rw-r--r--drivers/media/video/mt9t112.c16
-rw-r--r--drivers/media/video/mt9v011.c13
-rw-r--r--drivers/media/video/mt9v022.c18
-rw-r--r--drivers/media/video/mt9v032.c21
-rw-r--r--drivers/media/video/mx1_camera.c2
-rw-r--r--drivers/media/video/mx2_camera.c1301
-rw-r--r--drivers/media/video/mx2_emmaprp.c1008
-rw-r--r--drivers/media/video/mx3_camera.c21
-rw-r--r--drivers/media/video/noon010pc30.c15
-rw-r--r--drivers/media/video/omap/omap_vout.c236
-rw-r--r--drivers/media/video/omap/omap_vout_vrfb.c2
-rw-r--r--drivers/media/video/omap/omap_voutdef.h2
-rw-r--r--drivers/media/video/omap1_camera.c16
-rw-r--r--drivers/media/video/omap24xxcam.c19
-rw-r--r--drivers/media/video/omap3isp/isp.c72
-rw-r--r--drivers/media/video/omap3isp/ispccdc.c12
-rw-r--r--drivers/media/video/omap3isp/ispccdc.h2
-rw-r--r--drivers/media/video/omap3isp/ispccp2.c22
-rw-r--r--drivers/media/video/omap3isp/ispccp2.h3
-rw-r--r--drivers/media/video/omap3isp/ispcsi2.c18
-rw-r--r--drivers/media/video/omap3isp/ispcsi2.h2
-rw-r--r--drivers/media/video/omap3isp/isppreview.c25
-rw-r--r--drivers/media/video/omap3isp/isppreview.h2
-rw-r--r--drivers/media/video/omap3isp/ispresizer.c7
-rw-r--r--drivers/media/video/omap3isp/ispresizer.h1
-rw-r--r--drivers/media/video/omap3isp/ispvideo.c27
-rw-r--r--drivers/media/video/omap3isp/ispvideo.h8
-rw-r--r--drivers/media/video/ov2640.c16
-rw-r--r--drivers/media/video/ov5642.c13
-rw-r--r--drivers/media/video/ov6650.c15
-rw-r--r--drivers/media/video/ov7670.c15
-rw-r--r--drivers/media/video/ov772x.c17
-rw-r--r--drivers/media/video/ov9640.c13
-rw-r--r--drivers/media/video/ov9740.c13
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c10
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c1
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c935
-rw-r--r--drivers/media/video/pwc/pwc-dec1.c16
-rw-r--r--drivers/media/video/pwc/pwc-dec1.h6
-rw-r--r--drivers/media/video/pwc/pwc-dec23.c307
-rw-r--r--drivers/media/video/pwc/pwc-dec23.h14
-rw-r--r--drivers/media/video/pwc/pwc-if.c460
-rw-r--r--drivers/media/video/pwc/pwc-kiara.h2
-rw-r--r--drivers/media/video/pwc/pwc-misc.c88
-rw-r--r--drivers/media/video/pwc/pwc-timon.h2
-rw-r--r--drivers/media/video/pwc/pwc-uncompress.c46
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c324
-rw-r--r--drivers/media/video/pwc/pwc.h78
-rw-r--r--drivers/media/video/pxa_camera.c21
-rw-r--r--drivers/media/video/rj54n1cb0c.c13
-rw-r--r--drivers/media/video/s2255drv.c33
-rw-r--r--drivers/media/video/s5k6aa.c15
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c139
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c225
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h32
-rw-r--r--drivers/media/video/s5p-fimc/fimc-mdevice.c13
-rw-r--r--drivers/media/video/s5p-fimc/fimc-reg.c53
-rw-r--r--drivers/media/video/s5p-fimc/mipi-csis.c133
-rw-r--r--drivers/media/video/s5p-fimc/mipi-csis.h3
-rw-r--r--drivers/media/video/s5p-fimc/regs-fimc.h5
-rw-r--r--drivers/media/video/s5p-g2d/Makefile3
-rw-r--r--drivers/media/video/s5p-g2d/g2d-hw.c109
-rw-r--r--drivers/media/video/s5p-g2d/g2d-regs.h115
-rw-r--r--drivers/media/video/s5p-g2d/g2d.c848
-rw-r--r--drivers/media/video/s5p-g2d/g2d.h87
-rw-r--r--drivers/media/video/s5p-jpeg/Makefile2
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.c1563
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.h152
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-hw.h357
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-regs.h170
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc.c25
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_dec.c2
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_pm.c24
-rw-r--r--drivers/media/video/s5p-tv/Kconfig10
-rw-r--r--drivers/media/video/s5p-tv/Makefile2
-rw-r--r--drivers/media/video/s5p-tv/hdmi_drv.c150
-rw-r--r--drivers/media/video/s5p-tv/hdmiphy_drv.c12
-rw-r--r--drivers/media/video/s5p-tv/mixer.h14
-rw-r--r--drivers/media/video/s5p-tv/mixer_drv.c2
-rw-r--r--drivers/media/video/s5p-tv/mixer_grp_layer.c157
-rw-r--r--drivers/media/video/s5p-tv/mixer_video.c343
-rw-r--r--drivers/media/video/s5p-tv/mixer_vp_layer.c108
-rw-r--r--drivers/media/video/s5p-tv/sdo_drv.c48
-rw-r--r--drivers/media/video/s5p-tv/sii9234_drv.c432
-rw-r--r--drivers/media/video/saa6588.c13
-rw-r--r--drivers/media/video/saa7110.c13
-rw-r--r--drivers/media/video/saa7115.c15
-rw-r--r--drivers/media/video/saa7127.c13
-rw-r--r--drivers/media/video/saa7134/Makefile8
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c13
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c92
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c1
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c77
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c14
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c86
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c65
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/video/saa7134/saa7134.h7
-rw-r--r--drivers/media/video/saa7164/Makefile8
-rw-r--r--drivers/media/video/saa7164/saa7164-bus.c4
-rw-r--r--drivers/media/video/saa7164/saa7164-cards.c4
-rw-r--r--drivers/media/video/saa7164/saa7164-encoder.c6
-rw-r--r--drivers/media/video/saa7164/saa7164-vbi.c6
-rw-r--r--drivers/media/video/saa717x.c13
-rw-r--r--drivers/media/video/saa7185.c13
-rw-r--r--drivers/media/video/saa7191.c13
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c46
-rw-r--r--drivers/media/video/sh_mobile_csi2.c13
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c4
-rw-r--r--drivers/media/video/soc_camera.c36
-rw-r--r--drivers/media/video/soc_camera_platform.c13
-rw-r--r--drivers/media/video/sr030pc30.c13
-rw-r--r--drivers/media/video/stk-webcam.c8
-rw-r--r--drivers/media/video/tda7432.c13
-rw-r--r--drivers/media/video/tda9840.c13
-rw-r--r--drivers/media/video/tea6415c.c13
-rw-r--r--drivers/media/video/tea6420.c13
-rw-r--r--drivers/media/video/ths7303.c14
-rw-r--r--drivers/media/video/timblogiw.c19
-rw-r--r--drivers/media/video/tlg2300/pd-common.h2
-rw-r--r--drivers/media/video/tlg2300/pd-dvb.c22
-rw-r--r--drivers/media/video/tlg2300/pd-main.c4
-rw-r--r--drivers/media/video/tlv320aic23b.c13
-rw-r--r--drivers/media/video/tm6000/Kconfig6
-rw-r--r--drivers/media/video/tm6000/tm6000-alsa.c23
-rw-r--r--drivers/media/video/tm6000/tm6000-cards.c35
-rw-r--r--drivers/media/video/tm6000/tm6000-core.c86
-rw-r--r--drivers/media/video/tm6000/tm6000-dvb.c21
-rw-r--r--drivers/media/video/tm6000/tm6000-i2c.c8
-rw-r--r--drivers/media/video/tm6000/tm6000-input.c408
-rw-r--r--drivers/media/video/tm6000/tm6000-regs.h14
-rw-r--r--drivers/media/video/tm6000/tm6000-stds.c89
-rw-r--r--drivers/media/video/tm6000/tm6000-video.c21
-rw-r--r--drivers/media/video/tm6000/tm6000.h3
-rw-r--r--drivers/media/video/tuner-core.c29
-rw-r--r--drivers/media/video/tvaudio.c13
-rw-r--r--drivers/media/video/tveeprom.c10
-rw-r--r--drivers/media/video/tvp514x.c15
-rw-r--r--drivers/media/video/tvp5150.c212
-rw-r--r--drivers/media/video/tvp7002.c27
-rw-r--r--drivers/media/video/tw9910.c16
-rw-r--r--drivers/media/video/upd64031a.c13
-rw-r--r--drivers/media/video/upd64083.c15
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c46
-rw-r--r--drivers/media/video/uvc/Kconfig1
-rw-r--r--drivers/media/video/uvc/Makefile2
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c19
-rw-r--r--drivers/media/video/uvc/uvc_debugfs.c136
-rw-r--r--drivers/media/video/uvc/uvc_driver.c41
-rw-r--r--drivers/media/video/uvc/uvc_isight.c10
-rw-r--r--drivers/media/video/uvc/uvc_queue.c564
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c236
-rw-r--r--drivers/media/video/uvc/uvc_video.c653
-rw-r--r--drivers/media/video/uvc/uvcvideo.h128
-rw-r--r--drivers/media/video/v4l2-common.c1
-rw-r--r--drivers/media/video/v4l2-compat-ioctl32.c24
-rw-r--r--drivers/media/video/v4l2-ctrls.c150
-rw-r--r--drivers/media/video/v4l2-dev.c17
-rw-r--r--drivers/media/video/v4l2-device.c4
-rw-r--r--drivers/media/video/v4l2-ioctl.c170
-rw-r--r--drivers/media/video/v4l2-subdev.c12
-rw-r--r--drivers/media/video/via-camera.c26
-rw-r--r--drivers/media/video/videobuf-dvb.c7
-rw-r--r--drivers/media/video/videobuf2-core.c118
-rw-r--r--drivers/media/video/videobuf2-dma-sg.c3
-rw-r--r--drivers/media/video/videobuf2-memops.c28
-rw-r--r--drivers/media/video/videobuf2-vmalloc.c114
-rw-r--r--drivers/media/video/vino.c2
-rw-r--r--drivers/media/video/vivi.c26
-rw-r--r--drivers/media/video/vp27smpx.c13
-rw-r--r--drivers/media/video/vpx3220.c13
-rw-r--r--drivers/media/video/vs6624.c928
-rw-r--r--drivers/media/video/vs6624_regs.h337
-rw-r--r--drivers/media/video/w9966.c4
-rw-r--r--drivers/media/video/wm8739.c13
-rw-r--r--drivers/media/video/wm8775.c13
-rw-r--r--drivers/media/video/zoran/zoran_device.c2
-rw-r--r--drivers/media/video/zoran/zoran_driver.c1
-rw-r--r--drivers/media/video/zoran/zr36060.c2
612 files changed, 46349 insertions, 18763 deletions
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 996302ae210e..4a6d5cef3964 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -26,7 +26,7 @@ config MEDIA_TUNER
select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
- select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && EXPERIMENTAL
select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
@@ -116,6 +116,13 @@ config MEDIA_TUNER_MT2060
help
A driver for the silicon IF tuner MT2060 from Microtune.
+config MEDIA_TUNER_MT2063
+ tristate "Microtune MT2063 silicon IF tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A driver for the silicon IF tuner MT2063 from Microtune.
+
config MEDIA_TUNER_MT2266
tristate "Microtune MT2266 silicon tuner"
depends on VIDEO_MEDIA && I2C
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index 196c12a55f9a..f80407eb8998 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o
obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o
obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o
obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
@@ -28,5 +29,5 @@ obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c
index 9883617b7862..ba84936aafd6 100644
--- a/drivers/media/common/tuners/max2165.c
+++ b/drivers/media/common/tuners/max2165.c
@@ -151,7 +151,7 @@ static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw)
{
u8 val;
- if (bw == BANDWIDTH_8_MHZ)
+ if (bw == 8000000)
val = priv->bb_filter_8mhz_cfg;
else
val = priv->bb_filter_7mhz_cfg;
@@ -168,7 +168,7 @@ int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction)
int i;
if (0 == divisor)
- return -1;
+ return -EINVAL;
q = dividend / divisor;
remainder = dividend - q * divisor;
@@ -194,10 +194,13 @@ static int max2165_set_rf(struct max2165_priv *priv, u32 freq)
u8 tf_ntch;
u32 t;
u32 quotient, fraction;
+ int ret;
/* Set PLL divider according to RF frequency */
- fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
- &quotient, &fraction);
+ ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
+ &quotient, &fraction);
+ if (ret != 0)
+ return ret;
/* 20-bit fraction */
fraction >>= 12;
@@ -257,39 +260,28 @@ static void max2165_debug_status(struct max2165_priv *priv)
dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc);
}
-static int max2165_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int max2165_set_params(struct dvb_frontend *fe)
{
struct max2165_priv *priv = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
- dprintk("%s() frequency=%d (Hz)\n", __func__, params->frequency);
- if (fe->ops.info.type == FE_ATSC) {
- return -EINVAL;
- } else if (fe->ops.info.type == FE_OFDM) {
- dprintk("%s() OFDM\n", __func__);
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
- return -EINVAL;
- case BANDWIDTH_7_MHZ:
- case BANDWIDTH_8_MHZ:
- priv->frequency = params->frequency;
- priv->bandwidth = params->u.ofdm.bandwidth;
- break;
- default:
- printk(KERN_ERR "MAX2165 bandwidth not set!\n");
- return -EINVAL;
- }
- } else {
- printk(KERN_ERR "MAX2165 modulation type not supported!\n");
+ switch (c->bandwidth_hz) {
+ case 7000000:
+ case 8000000:
+ priv->frequency = c->frequency;
+ break;
+ default:
+ printk(KERN_INFO "MAX2165: bandwidth %d Hz not supported.\n",
+ c->bandwidth_hz);
return -EINVAL;
}
- dprintk("%s() frequency=%d\n", __func__, priv->frequency);
+ dprintk("%s() frequency=%d\n", __func__, c->frequency);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- max2165_set_bandwidth(priv, priv->bandwidth);
+ max2165_set_bandwidth(priv, c->bandwidth_hz);
ret = max2165_set_rf(priv, priv->frequency);
mdelay(50);
max2165_debug_status(priv);
@@ -370,7 +362,7 @@ static int max2165_init(struct dvb_frontend *fe)
max2165_read_rom_table(priv);
- max2165_set_bandwidth(priv, BANDWIDTH_8_MHZ);
+ max2165_set_bandwidth(priv, 8000000);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
diff --git a/drivers/media/common/tuners/mc44s803.c b/drivers/media/common/tuners/mc44s803.c
index fe5c4b8d83ee..5ddce7e326f7 100644
--- a/drivers/media/common/tuners/mc44s803.c
+++ b/drivers/media/common/tuners/mc44s803.c
@@ -214,22 +214,22 @@ exit:
return err;
}
-static int mc44s803_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int mc44s803_set_params(struct dvb_frontend *fe)
{
struct mc44s803_priv *priv = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u32 r1, r2, n1, n2, lo1, lo2, freq, val;
int err;
- priv->frequency = params->frequency;
+ priv->frequency = c->frequency;
r1 = MC44S803_OSC / 1000000;
r2 = MC44S803_OSC / 100000;
- n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000;
+ n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000;
freq = MC44S803_OSC / r1 * n1;
lo1 = ((60 * n1) + (r1 / 2)) / r1;
- freq = freq - params->frequency;
+ freq = freq - c->frequency;
n2 = (freq - MC44S803_IF2 + 50000) / 100000;
lo2 = ((60 * n2) + (r2 / 2)) / r2;
diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/common/tuners/mt2060.c
index 2d0e7689c6a2..13381de58a84 100644
--- a/drivers/media/common/tuners/mt2060.c
+++ b/drivers/media/common/tuners/mt2060.c
@@ -153,8 +153,9 @@ static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2)
#define IF2 36150 // IF2 frequency = 36.150 MHz
#define FREF 16000 // Quartz oscillator 16 MHz
-static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int mt2060_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct mt2060_priv *priv;
int ret=0;
int i=0;
@@ -176,8 +177,7 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
mt2060_writeregs(priv,b,2);
- freq = params->frequency / 1000; // Hz -> kHz
- priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+ freq = c->frequency / 1000; /* Hz -> kHz */
f_lo1 = freq + if1 * 1000;
f_lo1 = (f_lo1 / 250) * 250;
@@ -293,10 +293,9 @@ static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency)
return 0;
}
-static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+static int mt2060_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
- struct mt2060_priv *priv = fe->tuner_priv;
- *bandwidth = priv->bandwidth;
+ *frequency = IF2 * 1000;
return 0;
}
@@ -356,7 +355,7 @@ static const struct dvb_tuner_ops mt2060_tuner_ops = {
.set_params = mt2060_set_params,
.get_frequency = mt2060_get_frequency,
- .get_bandwidth = mt2060_get_bandwidth
+ .get_if_frequency = mt2060_get_if_frequency,
};
/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */
diff --git a/drivers/media/common/tuners/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h
index 5eaccdefd0b0..2b60de6c707d 100644
--- a/drivers/media/common/tuners/mt2060_priv.h
+++ b/drivers/media/common/tuners/mt2060_priv.h
@@ -97,7 +97,6 @@ struct mt2060_priv {
struct i2c_adapter *i2c;
u32 frequency;
- u32 bandwidth;
u16 if1_freq;
u8 fmfreq;
};
diff --git a/drivers/media/common/tuners/mt2063.c b/drivers/media/common/tuners/mt2063.c
new file mode 100644
index 000000000000..0ed9091ff48e
--- /dev/null
+++ b/drivers/media/common/tuners/mt2063.c
@@ -0,0 +1,2307 @@
+/*
+ * Driver for mt2063 Micronas tuner
+ *
+ * Copyright (c) 2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This driver came from a driver originally written by:
+ * Henry Wang <Henry.wang@AzureWave.com>
+ * Made publicly available by Terratec, at:
+ * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
+ * The original driver's license is GPL, as declared with MODULE_LICENSE()
+ *
+ * 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 under version 2 of the License.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "mt2063.h"
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Set Verbosity level");
+
+#define dprintk(level, fmt, arg...) do { \
+if (debug >= level) \
+ printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg); \
+} while (0)
+
+
+/* positive error codes used internally */
+
+/* Info: Unavoidable LO-related spur may be present in the output */
+#define MT2063_SPUR_PRESENT_ERR (0x00800000)
+
+/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */
+#define MT2063_SPUR_CNT_MASK (0x001f0000)
+#define MT2063_SPUR_SHIFT (16)
+
+/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
+#define MT2063_UPC_RANGE (0x04000000)
+
+/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
+#define MT2063_DNC_RANGE (0x08000000)
+
+/*
+ * Constant defining the version of the following structure
+ * and therefore the API for this code.
+ *
+ * When compiling the tuner driver, the preprocessor will
+ * check against this version number to make sure that
+ * it matches the version that the tuner driver knows about.
+ */
+
+/* DECT Frequency Avoidance */
+#define MT2063_DECT_AVOID_US_FREQS 0x00000001
+
+#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002
+
+#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
+
+#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
+
+enum MT2063_DECT_Avoid_Type {
+ MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */
+ MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */
+ MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */
+ MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */
+};
+
+#define MT2063_MAX_ZONES 48
+
+struct MT2063_ExclZone_t {
+ u32 min_;
+ u32 max_;
+ struct MT2063_ExclZone_t *next_;
+};
+
+/*
+ * Structure of data needed for Spur Avoidance
+ */
+struct MT2063_AvoidSpursData_t {
+ u32 f_ref;
+ u32 f_in;
+ u32 f_LO1;
+ u32 f_if1_Center;
+ u32 f_if1_Request;
+ u32 f_if1_bw;
+ u32 f_LO2;
+ u32 f_out;
+ u32 f_out_bw;
+ u32 f_LO1_Step;
+ u32 f_LO2_Step;
+ u32 f_LO1_FracN_Avoid;
+ u32 f_LO2_FracN_Avoid;
+ u32 f_zif_bw;
+ u32 f_min_LO_Separation;
+ u32 maxH1;
+ u32 maxH2;
+ enum MT2063_DECT_Avoid_Type avoidDECT;
+ u32 bSpurPresent;
+ u32 bSpurAvoided;
+ u32 nSpursFound;
+ u32 nZones;
+ struct MT2063_ExclZone_t *freeZones;
+ struct MT2063_ExclZone_t *usedZones;
+ struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
+};
+
+/*
+ * Parameter for function MT2063_SetPowerMask that specifies the power down
+ * of various sections of the MT2063.
+ */
+enum MT2063_Mask_Bits {
+ MT2063_REG_SD = 0x0040, /* Shutdown regulator */
+ MT2063_SRO_SD = 0x0020, /* Shutdown SRO */
+ MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */
+ MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */
+ MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */
+ MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */
+ MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */
+ MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */
+ MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */
+ MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */
+ MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */
+ MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */
+ MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */
+ MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */
+ MT2063_NONE_SD = 0x0000 /* No shutdown bits */
+};
+
+/*
+ * Possible values for MT2063_DNC_OUTPUT
+ */
+enum MT2063_DNC_Output_Enable {
+ MT2063_DNC_NONE = 0,
+ MT2063_DNC_1,
+ MT2063_DNC_2,
+ MT2063_DNC_BOTH
+};
+
+/*
+ * Two-wire serial bus subaddresses of the tuner registers.
+ * Also known as the tuner's register addresses.
+ */
+enum MT2063_Register_Offsets {
+ MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */
+ MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */
+ MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */
+ MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */
+ MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */
+ MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */
+ MT2063_REG_RSVD_06, /* 0x06: Reserved */
+ MT2063_REG_LO_STATUS, /* 0x07: LO Status */
+ MT2063_REG_FIFFC, /* 0x08: FIFF Center */
+ MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */
+ MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */
+ MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */
+ MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */
+ MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */
+ MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */
+ MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */
+ MT2063_REG_RSVD_10, /* 0x10: Reserved */
+ MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */
+ MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */
+ MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */
+ MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */
+ MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */
+ MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */
+ MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */
+ MT2063_REG_RF_OV, /* 0x18: RF Attn Override */
+ MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */
+ MT2063_REG_LNA_TGT, /* 0x1A: Reserved */
+ MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */
+ MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */
+ MT2063_REG_RSVD_1D, /* 0x1D: Reserved */
+ MT2063_REG_RSVD_1E, /* 0x1E: Reserved */
+ MT2063_REG_RSVD_1F, /* 0x1F: Reserved */
+ MT2063_REG_RSVD_20, /* 0x20: Reserved */
+ MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */
+ MT2063_REG_RSVD_22, /* 0x22: Reserved */
+ MT2063_REG_RSVD_23, /* 0x23: Reserved */
+ MT2063_REG_RSVD_24, /* 0x24: Reserved */
+ MT2063_REG_RSVD_25, /* 0x25: Reserved */
+ MT2063_REG_RSVD_26, /* 0x26: Reserved */
+ MT2063_REG_RSVD_27, /* 0x27: Reserved */
+ MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */
+ MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */
+ MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */
+ MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */
+ MT2063_REG_CTRL_2C, /* 0x2C: Reserved */
+ MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */
+ MT2063_REG_RSVD_2E, /* 0x2E: Reserved */
+ MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */
+ MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */
+ MT2063_REG_RSVD_31, /* 0x31: Reserved */
+ MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */
+ MT2063_REG_RSVD_33, /* 0x33: Reserved */
+ MT2063_REG_RSVD_34, /* 0x34: Reserved */
+ MT2063_REG_RSVD_35, /* 0x35: Reserved */
+ MT2063_REG_RSVD_36, /* 0x36: Reserved */
+ MT2063_REG_RSVD_37, /* 0x37: Reserved */
+ MT2063_REG_RSVD_38, /* 0x38: Reserved */
+ MT2063_REG_RSVD_39, /* 0x39: Reserved */
+ MT2063_REG_RSVD_3A, /* 0x3A: Reserved */
+ MT2063_REG_RSVD_3B, /* 0x3B: Reserved */
+ MT2063_REG_RSVD_3C, /* 0x3C: Reserved */
+ MT2063_REG_END_REGS
+};
+
+struct mt2063_state {
+ struct i2c_adapter *i2c;
+
+ bool init;
+
+ const struct mt2063_config *config;
+ struct dvb_tuner_ops ops;
+ struct dvb_frontend *frontend;
+ struct tuner_state status;
+
+ u32 frequency;
+ u32 srate;
+ u32 bandwidth;
+ u32 reference;
+
+ u32 tuner_id;
+ struct MT2063_AvoidSpursData_t AS_Data;
+ u32 f_IF1_actual;
+ u32 rcvr_mode;
+ u32 ctfilt_sw;
+ u32 CTFiltMax[31];
+ u32 num_regs;
+ u8 reg[MT2063_REG_END_REGS];
+};
+
+/*
+ * mt2063_write - Write data into the I2C bus
+ */
+static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len)
+{
+ struct dvb_frontend *fe = state->frontend;
+ int ret;
+ u8 buf[60];
+ struct i2c_msg msg = {
+ .addr = state->config->tuner_address,
+ .flags = 0,
+ .buf = buf,
+ .len = len + 1
+ };
+
+ dprintk(2, "\n");
+
+ msg.buf[0] = reg;
+ memcpy(msg.buf + 1, data, len);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ ret = i2c_transfer(state->i2c, &msg, 1);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (ret < 0)
+ printk(KERN_ERR "%s error ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+/*
+ * mt2063_write - Write register data into the I2C bus, caching the value
+ */
+static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val)
+{
+ u32 status;
+
+ dprintk(2, "\n");
+
+ if (reg >= MT2063_REG_END_REGS)
+ return -ERANGE;
+
+ status = mt2063_write(state, reg, &val, 1);
+ if (status < 0)
+ return status;
+
+ state->reg[reg] = val;
+
+ return 0;
+}
+
+/*
+ * mt2063_read - Read data from the I2C bus
+ */
+static u32 mt2063_read(struct mt2063_state *state,
+ u8 subAddress, u8 *pData, u32 cnt)
+{
+ u32 status = 0; /* Status to be returned */
+ struct dvb_frontend *fe = state->frontend;
+ u32 i = 0;
+
+ dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ for (i = 0; i < cnt; i++) {
+ u8 b0[] = { subAddress + i };
+ struct i2c_msg msg[] = {
+ {
+ .addr = state->config->tuner_address,
+ .flags = 0,
+ .buf = b0,
+ .len = 1
+ }, {
+ .addr = state->config->tuner_address,
+ .flags = I2C_M_RD,
+ .buf = pData + i,
+ .len = 1
+ }
+ };
+
+ status = i2c_transfer(state->i2c, msg, 2);
+ dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n",
+ subAddress + i, status, *(pData + i));
+ if (status < 0)
+ break;
+ }
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (status < 0)
+ printk(KERN_ERR "Can't read from address 0x%02x,\n",
+ subAddress + i);
+
+ return status;
+}
+
+/*
+ * FIXME: Is this really needed?
+ */
+static int MT2063_Sleep(struct dvb_frontend *fe)
+{
+ /*
+ * ToDo: Add code here to implement a OS blocking
+ */
+ msleep(100);
+
+ return 0;
+}
+
+/*
+ * Microtune spur avoidance
+ */
+
+/* Implement ceiling, floor functions. */
+#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
+#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
+
+struct MT2063_FIFZone_t {
+ s32 min_;
+ s32 max_;
+};
+
+static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
+ *pAS_Info,
+ struct MT2063_ExclZone_t *pPrevNode)
+{
+ struct MT2063_ExclZone_t *pNode;
+
+ dprintk(2, "\n");
+
+ /* Check for a node in the free list */
+ if (pAS_Info->freeZones != NULL) {
+ /* Use one from the free list */
+ pNode = pAS_Info->freeZones;
+ pAS_Info->freeZones = pNode->next_;
+ } else {
+ /* Grab a node from the array */
+ pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
+ }
+
+ if (pPrevNode != NULL) {
+ pNode->next_ = pPrevNode->next_;
+ pPrevNode->next_ = pNode;
+ } else { /* insert at the beginning of the list */
+
+ pNode->next_ = pAS_Info->usedZones;
+ pAS_Info->usedZones = pNode;
+ }
+
+ pAS_Info->nZones++;
+ return pNode;
+}
+
+static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
+ *pAS_Info,
+ struct MT2063_ExclZone_t *pPrevNode,
+ struct MT2063_ExclZone_t
+ *pNodeToRemove)
+{
+ struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
+
+ dprintk(2, "\n");
+
+ /* Make previous node point to the subsequent node */
+ if (pPrevNode != NULL)
+ pPrevNode->next_ = pNext;
+
+ /* Add pNodeToRemove to the beginning of the freeZones */
+ pNodeToRemove->next_ = pAS_Info->freeZones;
+ pAS_Info->freeZones = pNodeToRemove;
+
+ /* Decrement node count */
+ pAS_Info->nZones--;
+
+ return pNext;
+}
+
+/*
+ * MT_AddExclZone()
+ *
+ * Add (and merge) an exclusion zone into the list.
+ * If the range (f_min, f_max) is totally outside the
+ * 1st IF BW, ignore the entry.
+ * If the range (f_min, f_max) is negative, ignore the entry.
+ */
+static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
+ u32 f_min, u32 f_max)
+{
+ struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
+ struct MT2063_ExclZone_t *pPrev = NULL;
+ struct MT2063_ExclZone_t *pNext = NULL;
+
+ dprintk(2, "\n");
+
+ /* Check to see if this overlaps the 1st IF filter */
+ if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
+ && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
+ && (f_min < f_max)) {
+ /*
+ * 1 2 3 4 5 6
+ *
+ * New entry: |---| |--| |--| |-| |---| |--|
+ * or or or or or
+ * Existing: |--| |--| |--| |---| |-| |--|
+ */
+
+ /* Check for our place in the list */
+ while ((pNode != NULL) && (pNode->max_ < f_min)) {
+ pPrev = pNode;
+ pNode = pNode->next_;
+ }
+
+ if ((pNode != NULL) && (pNode->min_ < f_max)) {
+ /* Combine me with pNode */
+ if (f_min < pNode->min_)
+ pNode->min_ = f_min;
+ if (f_max > pNode->max_)
+ pNode->max_ = f_max;
+ } else {
+ pNode = InsertNode(pAS_Info, pPrev);
+ pNode->min_ = f_min;
+ pNode->max_ = f_max;
+ }
+
+ /* Look for merging possibilities */
+ pNext = pNode->next_;
+ while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
+ if (pNext->max_ > pNode->max_)
+ pNode->max_ = pNext->max_;
+ /* Remove pNext, return ptr to pNext->next */
+ pNext = RemoveNode(pAS_Info, pNode, pNext);
+ }
+ }
+}
+
+/*
+ * Reset all exclusion zones.
+ * Add zones to protect the PLL FracN regions near zero
+ */
+static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
+{
+ u32 center;
+
+ dprintk(2, "\n");
+
+ pAS_Info->nZones = 0; /* this clears the used list */
+ pAS_Info->usedZones = NULL; /* reset ptr */
+ pAS_Info->freeZones = NULL; /* reset ptr */
+
+ center =
+ pAS_Info->f_ref *
+ ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
+ pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
+ while (center <
+ pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
+ pAS_Info->f_LO1_FracN_Avoid) {
+ /* Exclude LO1 FracN */
+ MT2063_AddExclZone(pAS_Info,
+ center - pAS_Info->f_LO1_FracN_Avoid,
+ center - 1);
+ MT2063_AddExclZone(pAS_Info, center + 1,
+ center + pAS_Info->f_LO1_FracN_Avoid);
+ center += pAS_Info->f_ref;
+ }
+
+ center =
+ pAS_Info->f_ref *
+ ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
+ pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
+ while (center <
+ pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
+ pAS_Info->f_LO2_FracN_Avoid) {
+ /* Exclude LO2 FracN */
+ MT2063_AddExclZone(pAS_Info,
+ center - pAS_Info->f_LO2_FracN_Avoid,
+ center - 1);
+ MT2063_AddExclZone(pAS_Info, center + 1,
+ center + pAS_Info->f_LO2_FracN_Avoid);
+ center += pAS_Info->f_ref;
+ }
+
+ if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
+ /* Exclude LO1 values that conflict with DECT channels */
+ MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
+ MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
+ MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
+ MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
+ MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
+ }
+
+ if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
+ MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
+ MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
+ MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
+ MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */
+ MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
+ MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
+ MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
+ MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
+ MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */
+ MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
+ }
+}
+
+/*
+ * MT_ChooseFirstIF - Choose the best available 1st IF
+ * If f_Desired is not excluded, choose that first.
+ * Otherwise, return the value closest to f_Center that is
+ * not excluded
+ */
+static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
+{
+ /*
+ * Update "f_Desired" to be the nearest "combinational-multiple" of
+ * "f_LO1_Step".
+ * The resulting number, F_LO1 must be a multiple of f_LO1_Step.
+ * And F_LO1 is the arithmetic sum of f_in + f_Center.
+ * Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
+ * However, the sum must be.
+ */
+ const u32 f_Desired =
+ pAS_Info->f_LO1_Step *
+ ((pAS_Info->f_if1_Request + pAS_Info->f_in +
+ pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
+ pAS_Info->f_in;
+ const u32 f_Step =
+ (pAS_Info->f_LO1_Step >
+ pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
+ f_LO2_Step;
+ u32 f_Center;
+ s32 i;
+ s32 j = 0;
+ u32 bDesiredExcluded = 0;
+ u32 bZeroExcluded = 0;
+ s32 tmpMin, tmpMax;
+ s32 bestDiff;
+ struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
+ struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
+
+ dprintk(2, "\n");
+
+ if (pAS_Info->nZones == 0)
+ return f_Desired;
+
+ /*
+ * f_Center needs to be an integer multiple of f_Step away
+ * from f_Desired
+ */
+ if (pAS_Info->f_if1_Center > f_Desired)
+ f_Center =
+ f_Desired +
+ f_Step *
+ ((pAS_Info->f_if1_Center - f_Desired +
+ f_Step / 2) / f_Step);
+ else
+ f_Center =
+ f_Desired -
+ f_Step *
+ ((f_Desired - pAS_Info->f_if1_Center +
+ f_Step / 2) / f_Step);
+
+ /*
+ * Take MT_ExclZones, center around f_Center and change the
+ * resolution to f_Step
+ */
+ while (pNode != NULL) {
+ /* floor function */
+ tmpMin =
+ floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
+
+ /* ceil function */
+ tmpMax =
+ ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
+
+ if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
+ bDesiredExcluded = 1;
+
+ if ((tmpMin < 0) && (tmpMax > 0))
+ bZeroExcluded = 1;
+
+ /* See if this zone overlaps the previous */
+ if ((j > 0) && (tmpMin < zones[j - 1].max_))
+ zones[j - 1].max_ = tmpMax;
+ else {
+ /* Add new zone */
+ zones[j].min_ = tmpMin;
+ zones[j].max_ = tmpMax;
+ j++;
+ }
+ pNode = pNode->next_;
+ }
+
+ /*
+ * If the desired is okay, return with it
+ */
+ if (bDesiredExcluded == 0)
+ return f_Desired;
+
+ /*
+ * If the desired is excluded and the center is okay, return with it
+ */
+ if (bZeroExcluded == 0)
+ return f_Center;
+
+ /* Find the value closest to 0 (f_Center) */
+ bestDiff = zones[0].min_;
+ for (i = 0; i < j; i++) {
+ if (abs(zones[i].min_) < abs(bestDiff))
+ bestDiff = zones[i].min_;
+ if (abs(zones[i].max_) < abs(bestDiff))
+ bestDiff = zones[i].max_;
+ }
+
+ if (bestDiff < 0)
+ return f_Center - ((u32) (-bestDiff) * f_Step);
+
+ return f_Center + (bestDiff * f_Step);
+}
+
+/**
+ * gcd() - Uses Euclid's algorithm
+ *
+ * @u, @v: Unsigned values whose GCD is desired.
+ *
+ * Returns THE greatest common divisor of u and v, if either value is 0,
+ * the other value is returned as the result.
+ */
+static u32 MT2063_gcd(u32 u, u32 v)
+{
+ u32 r;
+
+ while (v != 0) {
+ r = u % v;
+ u = v;
+ v = r;
+ }
+
+ return u;
+}
+
+/**
+ * IsSpurInBand() - Checks to see if a spur will be present within the IF's
+ * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
+ *
+ * ma mb mc md
+ * <--+-+-+-------------------+-------------------+-+-+-->
+ * | ^ 0 ^ |
+ * ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
+ * a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
+ *
+ * Note that some equations are doubled to prevent round-off
+ * problems when calculating fIFBW/2
+ *
+ * @pAS_Info: Avoid Spurs information block
+ * @fm: If spur, amount f_IF1 has to move negative
+ * @fp: If spur, amount f_IF1 has to move positive
+ *
+ * Returns 1 if an LO spur would be present, otherwise 0.
+ */
+static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
+ u32 *fm, u32 * fp)
+{
+ /*
+ ** Calculate LO frequency settings.
+ */
+ u32 n, n0;
+ const u32 f_LO1 = pAS_Info->f_LO1;
+ const u32 f_LO2 = pAS_Info->f_LO2;
+ const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
+ const u32 c = d - pAS_Info->f_out_bw;
+ const u32 f = pAS_Info->f_zif_bw / 2;
+ const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1;
+ s32 f_nsLO1, f_nsLO2;
+ s32 f_Spur;
+ u32 ma, mb, mc, md, me, mf;
+ u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
+
+ dprintk(2, "\n");
+
+ *fm = 0;
+
+ /*
+ ** For each edge (d, c & f), calculate a scale, based on the gcd
+ ** of f_LO1, f_LO2 and the edge value. Use the larger of this
+ ** gcd-based scale factor or f_Scale.
+ */
+ lo_gcd = MT2063_gcd(f_LO1, f_LO2);
+ gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale);
+ hgds = gd_Scale / 2;
+ gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale);
+ hgcs = gc_Scale / 2;
+ gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale);
+ hgfs = gf_Scale / 2;
+
+ n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2);
+
+ /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */
+ for (n = n0; n <= pAS_Info->maxH1; ++n) {
+ md = (n * ((f_LO1 + hgds) / gd_Scale) -
+ ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
+
+ /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */
+ if (md >= pAS_Info->maxH1)
+ break;
+
+ ma = (n * ((f_LO1 + hgds) / gd_Scale) +
+ ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
+
+ /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */
+ if (md == ma)
+ continue;
+
+ mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
+ ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
+ if (mc != md) {
+ f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
+ f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
+ f_Spur =
+ (gc_Scale * (f_nsLO1 - f_nsLO2)) +
+ n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
+
+ *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
+ *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
+ return 1;
+ }
+
+ /* Location of Zero-IF-spur to be checked */
+ me = (n * ((f_LO1 + hgfs) / gf_Scale) +
+ ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
+ mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
+ ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
+ if (me != mf) {
+ f_nsLO1 = n * (f_LO1 / gf_Scale);
+ f_nsLO2 = me * (f_LO2 / gf_Scale);
+ f_Spur =
+ (gf_Scale * (f_nsLO1 - f_nsLO2)) +
+ n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
+
+ *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
+ *fm = (((s32) f - f_Spur) / (me - n)) + 1;
+ return 1;
+ }
+
+ mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
+ ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
+ if (ma != mb) {
+ f_nsLO1 = n * (f_LO1 / gc_Scale);
+ f_nsLO2 = ma * (f_LO2 / gc_Scale);
+ f_Spur =
+ (gc_Scale * (f_nsLO1 - f_nsLO2)) +
+ n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
+
+ *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
+ *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
+ return 1;
+ }
+ }
+
+ /* No spurs found */
+ return 0;
+}
+
+/*
+ * MT_AvoidSpurs() - Main entry point to avoid spurs.
+ * Checks for existing spurs in present LO1, LO2 freqs
+ * and if present, chooses spur-free LO1, LO2 combination
+ * that tunes the same input/output frequencies.
+ */
+static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info)
+{
+ u32 status = 0;
+ u32 fm, fp; /* restricted range on LO's */
+ pAS_Info->bSpurAvoided = 0;
+ pAS_Info->nSpursFound = 0;
+
+ dprintk(2, "\n");
+
+ if (pAS_Info->maxH1 == 0)
+ return 0;
+
+ /*
+ * Avoid LO Generated Spurs
+ *
+ * Make sure that have no LO-related spurs within the IF output
+ * bandwidth.
+ *
+ * If there is an LO spur in this band, start at the current IF1 frequency
+ * and work out until we find a spur-free frequency or run up against the
+ * 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they
+ * will be unchanged if a spur-free setting is not found.
+ */
+ pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
+ if (pAS_Info->bSpurPresent) {
+ u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */
+ u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */
+ u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */
+ u32 delta_IF1;
+ u32 new_IF1;
+
+ /*
+ ** Spur was found, attempt to find a spur-free 1st IF
+ */
+ do {
+ pAS_Info->nSpursFound++;
+
+ /* Raise f_IF1_upper, if needed */
+ MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
+
+ /* Choose next IF1 that is closest to f_IF1_CENTER */
+ new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
+
+ if (new_IF1 > zfIF1) {
+ pAS_Info->f_LO1 += (new_IF1 - zfIF1);
+ pAS_Info->f_LO2 += (new_IF1 - zfIF1);
+ } else {
+ pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
+ pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
+ }
+ zfIF1 = new_IF1;
+
+ if (zfIF1 > pAS_Info->f_if1_Center)
+ delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
+ else
+ delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
+
+ pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
+ /*
+ * Continue while the new 1st IF is still within the 1st IF bandwidth
+ * and there is a spur in the band (again)
+ */
+ } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent);
+
+ /*
+ * Use the LO-spur free values found. If the search went all
+ * the way to the 1st IF band edge and always found spurs, just
+ * leave the original choice. It's as "good" as any other.
+ */
+ if (pAS_Info->bSpurPresent == 1) {
+ status |= MT2063_SPUR_PRESENT_ERR;
+ pAS_Info->f_LO1 = zfLO1;
+ pAS_Info->f_LO2 = zfLO2;
+ } else
+ pAS_Info->bSpurAvoided = 1;
+ }
+
+ status |=
+ ((pAS_Info->
+ nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
+
+ return status;
+}
+
+/*
+ * Constants used by the tuning algorithm
+ */
+#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */
+#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */
+#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */
+#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */
+#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */
+#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */
+#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */
+#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */
+#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */
+#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */
+#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */
+#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */
+#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */
+#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */
+#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */
+#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */
+#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */
+#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */
+
+/*
+ * Define the supported Part/Rev codes for the MT2063
+ */
+#define MT2063_B0 (0x9B)
+#define MT2063_B1 (0x9C)
+#define MT2063_B2 (0x9D)
+#define MT2063_B3 (0x9E)
+
+/**
+ * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
+ *
+ * @state: struct mt2063_state pointer
+ *
+ * This function returns 0, if no lock, 1 if locked and a value < 1 if error
+ */
+static unsigned int mt2063_lockStatus(struct mt2063_state *state)
+{
+ const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
+ const u32 nPollRate = 2; /* poll status bits every 2 ms */
+ const u32 nMaxLoops = nMaxWait / nPollRate;
+ const u8 LO1LK = 0x80;
+ u8 LO2LK = 0x08;
+ u32 status;
+ u32 nDelays = 0;
+
+ dprintk(2, "\n");
+
+ /* LO2 Lock bit was in a different place for B0 version */
+ if (state->tuner_id == MT2063_B0)
+ LO2LK = 0x40;
+
+ do {
+ status = mt2063_read(state, MT2063_REG_LO_STATUS,
+ &state->reg[MT2063_REG_LO_STATUS], 1);
+
+ if (status < 0)
+ return status;
+
+ if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
+ (LO1LK | LO2LK)) {
+ return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
+ }
+ msleep(nPollRate); /* Wait between retries */
+ } while (++nDelays < nMaxLoops);
+
+ /*
+ * Got no lock or partial lock
+ */
+ return 0;
+}
+
+/*
+ * Constants for setting receiver modes.
+ * (6 modes defined at this time, enumerated by mt2063_delivery_sys)
+ * (DNC1GC & DNC2GC are the values, which are used, when the specific
+ * DNC Output is selected, the other is always off)
+ *
+ * enum mt2063_delivery_sys
+ * -------------+----------------------------------------------
+ * Mode 0 : | MT2063_CABLE_QAM
+ * Mode 1 : | MT2063_CABLE_ANALOG
+ * Mode 2 : | MT2063_OFFAIR_COFDM
+ * Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
+ * Mode 4 : | MT2063_OFFAIR_ANALOG
+ * Mode 5 : | MT2063_OFFAIR_8VSB
+ * --------------+----------------------------------------------
+ *
+ * |<---------- Mode -------------->|
+ * Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
+ * ------------+-----+-----+-----+-----+-----+-----+
+ * RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
+ * LNARin | 0 | 0 | 3 | 3 | 3 | 3
+ * FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
+ * FIFFq | 0 | 0 | 0 | 0 | 0 | 0
+ * DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
+ * DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
+ * GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
+ * LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
+ * LNA Target | 44 | 43 | 43 | 43 | 43 | 43
+ * ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
+ * RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
+ * PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
+ * ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
+ * FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
+ * PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
+ */
+
+enum mt2063_delivery_sys {
+ MT2063_CABLE_QAM = 0,
+ MT2063_CABLE_ANALOG,
+ MT2063_OFFAIR_COFDM,
+ MT2063_OFFAIR_COFDM_SAWLESS,
+ MT2063_OFFAIR_ANALOG,
+ MT2063_OFFAIR_8VSB,
+ MT2063_NUM_RCVR_MODES
+};
+
+static const char *mt2063_mode_name[] = {
+ [MT2063_CABLE_QAM] = "digital cable",
+ [MT2063_CABLE_ANALOG] = "analog cable",
+ [MT2063_OFFAIR_COFDM] = "digital offair",
+ [MT2063_OFFAIR_COFDM_SAWLESS] = "digital offair without SAW",
+ [MT2063_OFFAIR_ANALOG] = "analog offair",
+ [MT2063_OFFAIR_8VSB] = "analog offair 8vsb",
+};
+
+static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 };
+static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 };
+static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 };
+static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 };
+static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 };
+static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 };
+static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 };
+static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 };
+static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
+static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 };
+static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 };
+static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
+static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 };
+static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
+
+/*
+ * mt2063_set_dnc_output_enable()
+ */
+static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state,
+ enum MT2063_DNC_Output_Enable *pValue)
+{
+ dprintk(2, "\n");
+
+ if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
+ if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
+ *pValue = MT2063_DNC_NONE;
+ else
+ *pValue = MT2063_DNC_2;
+ } else { /* DNC1 is on */
+ if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
+ *pValue = MT2063_DNC_1;
+ else
+ *pValue = MT2063_DNC_BOTH;
+ }
+ return 0;
+}
+
+/*
+ * mt2063_set_dnc_output_enable()
+ */
+static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state,
+ enum MT2063_DNC_Output_Enable nValue)
+{
+ u32 status = 0; /* Status to be returned */
+ u8 val = 0;
+
+ dprintk(2, "\n");
+
+ /* selects, which DNC output is used */
+ switch (nValue) {
+ case MT2063_DNC_NONE:
+ val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
+ if (state->reg[MT2063_REG_DNC_GAIN] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_DNC_GAIN,
+ val);
+
+ val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
+ if (state->reg[MT2063_REG_VGA_GAIN] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_VGA_GAIN,
+ val);
+
+ val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
+ if (state->reg[MT2063_REG_RSVD_20] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_RSVD_20,
+ val);
+
+ break;
+ case MT2063_DNC_1:
+ val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
+ if (state->reg[MT2063_REG_DNC_GAIN] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_DNC_GAIN,
+ val);
+
+ val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
+ if (state->reg[MT2063_REG_VGA_GAIN] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_VGA_GAIN,
+ val);
+
+ val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
+ if (state->reg[MT2063_REG_RSVD_20] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_RSVD_20,
+ val);
+
+ break;
+ case MT2063_DNC_2:
+ val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
+ if (state->reg[MT2063_REG_DNC_GAIN] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_DNC_GAIN,
+ val);
+
+ val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
+ if (state->reg[MT2063_REG_VGA_GAIN] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_VGA_GAIN,
+ val);
+
+ val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
+ if (state->reg[MT2063_REG_RSVD_20] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_RSVD_20,
+ val);
+
+ break;
+ case MT2063_DNC_BOTH:
+ val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
+ if (state->reg[MT2063_REG_DNC_GAIN] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_DNC_GAIN,
+ val);
+
+ val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
+ if (state->reg[MT2063_REG_VGA_GAIN] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_VGA_GAIN,
+ val);
+
+ val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
+ if (state->reg[MT2063_REG_RSVD_20] !=
+ val)
+ status |=
+ mt2063_setreg(state,
+ MT2063_REG_RSVD_20,
+ val);
+
+ break;
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/*
+ * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with
+ * the selected enum mt2063_delivery_sys type.
+ *
+ * (DNC1GC & DNC2GC are the values, which are used, when the specific
+ * DNC Output is selected, the other is always off)
+ *
+ * @state: ptr to mt2063_state structure
+ * @Mode: desired reciever delivery system
+ *
+ * Note: Register cache must be valid for it to work
+ */
+
+static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
+ enum mt2063_delivery_sys Mode)
+{
+ u32 status = 0; /* Status to be returned */
+ u8 val;
+ u32 longval;
+
+ dprintk(2, "\n");
+
+ if (Mode >= MT2063_NUM_RCVR_MODES)
+ status = -ERANGE;
+
+ /* RFAGCen */
+ if (status >= 0) {
+ val =
+ (state->
+ reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode]
+ ? 0x40 :
+ 0x00);
+ if (state->reg[MT2063_REG_PD1_TGT] != val)
+ status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
+ }
+
+ /* LNARin */
+ if (status >= 0) {
+ u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) |
+ (LNARIN[Mode] & 0x03);
+ if (state->reg[MT2063_REG_CTRL_2C] != val)
+ status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
+ }
+
+ /* FIFFQEN and FIFFQ */
+ if (status >= 0) {
+ val =
+ (state->
+ reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) |
+ (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
+ if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
+ status |=
+ mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
+ /* trigger FIFF calibration, needed after changing FIFFQ */
+ val =
+ (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
+ status |=
+ mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
+ val =
+ (state->
+ reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01);
+ status |=
+ mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
+ }
+ }
+
+ /* DNC1GC & DNC2GC */
+ status |= mt2063_get_dnc_output_enable(state, &longval);
+ status |= mt2063_set_dnc_output_enable(state, longval);
+
+ /* acLNAmax */
+ if (status >= 0) {
+ u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) |
+ (ACLNAMAX[Mode] & 0x1F);
+ if (state->reg[MT2063_REG_LNA_OV] != val)
+ status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
+ }
+
+ /* LNATGT */
+ if (status >= 0) {
+ u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) |
+ (LNATGT[Mode] & 0x3F);
+ if (state->reg[MT2063_REG_LNA_TGT] != val)
+ status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
+ }
+
+ /* ACRF */
+ if (status >= 0) {
+ u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) |
+ (ACRFMAX[Mode] & 0x1F);
+ if (state->reg[MT2063_REG_RF_OV] != val)
+ status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
+ }
+
+ /* PD1TGT */
+ if (status >= 0) {
+ u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) |
+ (PD1TGT[Mode] & 0x3F);
+ if (state->reg[MT2063_REG_PD1_TGT] != val)
+ status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
+ }
+
+ /* FIFATN */
+ if (status >= 0) {
+ u8 val = ACFIFMAX[Mode];
+ if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
+ val = 5;
+ val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) |
+ (val & 0x1F);
+ if (state->reg[MT2063_REG_FIF_OV] != val)
+ status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
+ }
+
+ /* PD2TGT */
+ if (status >= 0) {
+ u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) |
+ (PD2TGT[Mode] & 0x3F);
+ if (state->reg[MT2063_REG_PD2_TGT] != val)
+ status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
+ }
+
+ /* Ignore ATN Overload */
+ if (status >= 0) {
+ val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) |
+ (RFOVDIS[Mode] ? 0x80 : 0x00);
+ if (state->reg[MT2063_REG_LNA_TGT] != val)
+ status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
+ }
+
+ /* Ignore FIF Overload */
+ if (status >= 0) {
+ val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) |
+ (FIFOVDIS[Mode] ? 0x80 : 0x00);
+ if (state->reg[MT2063_REG_PD1_TGT] != val)
+ status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
+ }
+
+ if (status >= 0) {
+ state->rcvr_mode = Mode;
+ dprintk(1, "mt2063 mode changed to %s\n",
+ mt2063_mode_name[state->rcvr_mode]);
+ }
+
+ return status;
+}
+
+/*
+ * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various
+ * sections of the MT2063
+ *
+ * @Bits: Mask bits to be cleared.
+ *
+ * See definition of MT2063_Mask_Bits type for description
+ * of each of the power bits.
+ */
+static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state,
+ enum MT2063_Mask_Bits Bits)
+{
+ u32 status = 0;
+
+ dprintk(2, "\n");
+ Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
+ if ((Bits & 0xFF00) != 0) {
+ state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
+ status |=
+ mt2063_write(state,
+ MT2063_REG_PWR_2,
+ &state->reg[MT2063_REG_PWR_2], 1);
+ }
+ if ((Bits & 0xFF) != 0) {
+ state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
+ status |=
+ mt2063_write(state,
+ MT2063_REG_PWR_1,
+ &state->reg[MT2063_REG_PWR_1], 1);
+ }
+
+ return status;
+}
+
+/*
+ * MT2063_SoftwareShutdown() - Enables or disables software shutdown function.
+ * When Shutdown is 1, any section whose power
+ * mask is set will be shutdown.
+ */
+static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
+{
+ u32 status;
+
+ dprintk(2, "\n");
+ if (Shutdown == 1)
+ state->reg[MT2063_REG_PWR_1] |= 0x04;
+ else
+ state->reg[MT2063_REG_PWR_1] &= ~0x04;
+
+ status = mt2063_write(state,
+ MT2063_REG_PWR_1,
+ &state->reg[MT2063_REG_PWR_1], 1);
+
+ if (Shutdown != 1) {
+ state->reg[MT2063_REG_BYP_CTRL] =
+ (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
+ status |=
+ mt2063_write(state,
+ MT2063_REG_BYP_CTRL,
+ &state->reg[MT2063_REG_BYP_CTRL],
+ 1);
+ state->reg[MT2063_REG_BYP_CTRL] =
+ (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
+ status |=
+ mt2063_write(state,
+ MT2063_REG_BYP_CTRL,
+ &state->reg[MT2063_REG_BYP_CTRL],
+ 1);
+ }
+
+ return status;
+}
+
+static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
+{
+ return f_ref * (f_LO / f_ref)
+ + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
+}
+
+/**
+ * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom.
+ * This function preserves maximum precision without
+ * risk of overflow. It accurately calculates
+ * f_ref * num / denom to within 1 HZ with fixed math.
+ *
+ * @num : Fractional portion of the multiplier
+ * @denom: denominator portion of the ratio
+ * @f_Ref: SRO frequency.
+ *
+ * This calculation handles f_ref as two separate 14-bit fields.
+ * Therefore, a maximum value of 2^28-1 may safely be used for f_ref.
+ * This is the genesis of the magic number "14" and the magic mask value of
+ * 0x03FFF.
+ *
+ * This routine successfully handles denom values up to and including 2^18.
+ * Returns: f_ref * num / denom
+ */
+static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom)
+{
+ u32 t1 = (f_ref >> 14) * num;
+ u32 term1 = t1 / denom;
+ u32 loss = t1 % denom;
+ u32 term2 =
+ (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
+ return (term1 << 14) + term2;
+}
+
+/*
+ * CalcLO1Mult()- Calculates Integer divider value and the numerator
+ * value for a FracN PLL.
+ *
+ * This function assumes that the f_LO and f_Ref are
+ * evenly divisible by f_LO_Step.
+ *
+ * @Div: OUTPUT: Whole number portion of the multiplier
+ * @FracN: OUTPUT: Fractional portion of the multiplier
+ * @f_LO: desired LO frequency.
+ * @f_LO_Step: Minimum step size for the LO (in Hz).
+ * @f_Ref: SRO frequency.
+ * @f_Avoid: Range of PLL frequencies to avoid near integer multiples
+ * of f_Ref (in Hz).
+ *
+ * Returns: Recalculated LO frequency.
+ */
+static u32 MT2063_CalcLO1Mult(u32 *Div,
+ u32 *FracN,
+ u32 f_LO,
+ u32 f_LO_Step, u32 f_Ref)
+{
+ /* Calculate the whole number portion of the divider */
+ *Div = f_LO / f_Ref;
+
+ /* Calculate the numerator value (round to nearest f_LO_Step) */
+ *FracN =
+ (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
+ (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
+
+ return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
+}
+
+/**
+ * CalcLO2Mult() - Calculates Integer divider value and the numerator
+ * value for a FracN PLL.
+ *
+ * This function assumes that the f_LO and f_Ref are
+ * evenly divisible by f_LO_Step.
+ *
+ * @Div: OUTPUT: Whole number portion of the multiplier
+ * @FracN: OUTPUT: Fractional portion of the multiplier
+ * @f_LO: desired LO frequency.
+ * @f_LO_Step: Minimum step size for the LO (in Hz).
+ * @f_Ref: SRO frequency.
+ * @f_Avoid: Range of PLL frequencies to avoid near
+ * integer multiples of f_Ref (in Hz).
+ *
+ * Returns: Recalculated LO frequency.
+ */
+static u32 MT2063_CalcLO2Mult(u32 *Div,
+ u32 *FracN,
+ u32 f_LO,
+ u32 f_LO_Step, u32 f_Ref)
+{
+ /* Calculate the whole number portion of the divider */
+ *Div = f_LO / f_Ref;
+
+ /* Calculate the numerator value (round to nearest f_LO_Step) */
+ *FracN =
+ (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
+ (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
+
+ return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
+ 8191);
+}
+
+/*
+ * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be
+ * used for a given input frequency.
+ *
+ * @state: ptr to tuner data structure
+ * @f_in: RF input center frequency (in Hz).
+ *
+ * Returns: ClearTune filter number (0-31)
+ */
+static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
+{
+ u32 RFBand;
+ u32 idx; /* index loop */
+
+ /*
+ ** Find RF Band setting
+ */
+ RFBand = 31; /* def when f_in > all */
+ for (idx = 0; idx < 31; ++idx) {
+ if (state->CTFiltMax[idx] >= f_in) {
+ RFBand = idx;
+ break;
+ }
+ }
+ return RFBand;
+}
+
+/*
+ * MT2063_Tune() - Change the tuner's tuned frequency to RFin.
+ */
+static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
+{ /* RF input center frequency */
+
+ u32 status = 0;
+ u32 LO1; /* 1st LO register value */
+ u32 Num1; /* Numerator for LO1 reg. value */
+ u32 f_IF1; /* 1st IF requested */
+ u32 LO2; /* 2nd LO register value */
+ u32 Num2; /* Numerator for LO2 reg. value */
+ u32 ofLO1, ofLO2; /* last time's LO frequencies */
+ u8 fiffc = 0x80; /* FIFF center freq from tuner */
+ u32 fiffof; /* Offset from FIFF center freq */
+ const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
+ u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
+ u8 val;
+ u32 RFBand;
+
+ dprintk(2, "\n");
+ /* Check the input and output frequency ranges */
+ if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
+ return -EINVAL;
+
+ if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
+ || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
+ return -EINVAL;
+
+ /*
+ * Save original LO1 and LO2 register values
+ */
+ ofLO1 = state->AS_Data.f_LO1;
+ ofLO2 = state->AS_Data.f_LO2;
+
+ /*
+ * Find and set RF Band setting
+ */
+ if (state->ctfilt_sw == 1) {
+ val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
+ if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
+ status |=
+ mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val);
+ }
+ val = state->reg[MT2063_REG_CTUNE_OV];
+ RFBand = FindClearTuneFilter(state, f_in);
+ state->reg[MT2063_REG_CTUNE_OV] =
+ (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
+ | RFBand);
+ if (state->reg[MT2063_REG_CTUNE_OV] != val) {
+ status |=
+ mt2063_setreg(state, MT2063_REG_CTUNE_OV, val);
+ }
+ }
+
+ /*
+ * Read the FIFF Center Frequency from the tuner
+ */
+ if (status >= 0) {
+ status |=
+ mt2063_read(state,
+ MT2063_REG_FIFFC,
+ &state->reg[MT2063_REG_FIFFC], 1);
+ fiffc = state->reg[MT2063_REG_FIFFC];
+ }
+ /*
+ * Assign in the requested values
+ */
+ state->AS_Data.f_in = f_in;
+ /* Request a 1st IF such that LO1 is on a step size */
+ state->AS_Data.f_if1_Request =
+ MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
+ state->AS_Data.f_LO1_Step,
+ state->AS_Data.f_ref) - f_in;
+
+ /*
+ * Calculate frequency settings. f_IF1_FREQ + f_in is the
+ * desired LO1 frequency
+ */
+ MT2063_ResetExclZones(&state->AS_Data);
+
+ f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
+
+ state->AS_Data.f_LO1 =
+ MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
+ state->AS_Data.f_ref);
+
+ state->AS_Data.f_LO2 =
+ MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
+ state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
+
+ /*
+ * Check for any LO spurs in the output bandwidth and adjust
+ * the LO settings to avoid them if needed
+ */
+ status |= MT2063_AvoidSpurs(&state->AS_Data);
+ /*
+ * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
+ * Recalculate the LO frequencies and the values to be placed
+ * in the tuning registers.
+ */
+ state->AS_Data.f_LO1 =
+ MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
+ state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
+ state->AS_Data.f_LO2 =
+ MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
+ state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
+ state->AS_Data.f_LO2 =
+ MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
+ state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
+
+ /*
+ * Check the upconverter and downconverter frequency ranges
+ */
+ if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
+ || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
+ status |= MT2063_UPC_RANGE;
+ if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
+ || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
+ status |= MT2063_DNC_RANGE;
+ /* LO2 Lock bit was in a different place for B0 version */
+ if (state->tuner_id == MT2063_B0)
+ LO2LK = 0x40;
+
+ /*
+ * If we have the same LO frequencies and we're already locked,
+ * then skip re-programming the LO registers.
+ */
+ if ((ofLO1 != state->AS_Data.f_LO1)
+ || (ofLO2 != state->AS_Data.f_LO2)
+ || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
+ (LO1LK | LO2LK))) {
+ /*
+ * Calculate the FIFFOF register value
+ *
+ * IF1_Actual
+ * FIFFOF = ------------ - 8 * FIFFC - 4992
+ * f_ref/64
+ */
+ fiffof =
+ (state->AS_Data.f_LO1 -
+ f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
+ 4992;
+ if (fiffof > 0xFF)
+ fiffof = 0xFF;
+
+ /*
+ * Place all of the calculated values into the local tuner
+ * register fields.
+ */
+ if (status >= 0) {
+ state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
+ state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
+ state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
+ |(Num2 >> 12)); /* NUM2q (hi) */
+ state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
+ state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
+
+ /*
+ * Now write out the computed register values
+ * IMPORTANT: There is a required order for writing
+ * (0x05 must follow all the others).
+ */
+ status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */
+ if (state->tuner_id == MT2063_B0) {
+ /* Re-write the one-shot bits to trigger the tune operation */
+ status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
+ }
+ /* Write out the FIFF offset only if it's changing */
+ if (state->reg[MT2063_REG_FIFF_OFFSET] !=
+ (u8) fiffof) {
+ state->reg[MT2063_REG_FIFF_OFFSET] =
+ (u8) fiffof;
+ status |=
+ mt2063_write(state,
+ MT2063_REG_FIFF_OFFSET,
+ &state->
+ reg[MT2063_REG_FIFF_OFFSET],
+ 1);
+ }
+ }
+
+ /*
+ * Check for LO's locking
+ */
+
+ if (status < 0)
+ return status;
+
+ status = mt2063_lockStatus(state);
+ if (status < 0)
+ return status;
+ if (!status)
+ return -EINVAL; /* Couldn't lock */
+
+ /*
+ * If we locked OK, assign calculated data to mt2063_state structure
+ */
+ state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
+ }
+
+ return status;
+}
+
+static const u8 MT2063B0_defaults[] = {
+ /* Reg, Value */
+ 0x19, 0x05,
+ 0x1B, 0x1D,
+ 0x1C, 0x1F,
+ 0x1D, 0x0F,
+ 0x1E, 0x3F,
+ 0x1F, 0x0F,
+ 0x20, 0x3F,
+ 0x22, 0x21,
+ 0x23, 0x3F,
+ 0x24, 0x20,
+ 0x25, 0x3F,
+ 0x27, 0xEE,
+ 0x2C, 0x27, /* bit at 0x20 is cleared below */
+ 0x30, 0x03,
+ 0x2C, 0x07, /* bit at 0x20 is cleared here */
+ 0x2D, 0x87,
+ 0x2E, 0xAA,
+ 0x28, 0xE1, /* Set the FIFCrst bit here */
+ 0x28, 0xE0, /* Clear the FIFCrst bit here */
+ 0x00
+};
+
+/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
+static const u8 MT2063B1_defaults[] = {
+ /* Reg, Value */
+ 0x05, 0xF0,
+ 0x11, 0x10, /* New Enable AFCsd */
+ 0x19, 0x05,
+ 0x1A, 0x6C,
+ 0x1B, 0x24,
+ 0x1C, 0x28,
+ 0x1D, 0x8F,
+ 0x1E, 0x14,
+ 0x1F, 0x8F,
+ 0x20, 0x57,
+ 0x22, 0x21, /* New - ver 1.03 */
+ 0x23, 0x3C, /* New - ver 1.10 */
+ 0x24, 0x20, /* New - ver 1.03 */
+ 0x2C, 0x24, /* bit at 0x20 is cleared below */
+ 0x2D, 0x87, /* FIFFQ=0 */
+ 0x2F, 0xF3,
+ 0x30, 0x0C, /* New - ver 1.11 */
+ 0x31, 0x1B, /* New - ver 1.11 */
+ 0x2C, 0x04, /* bit at 0x20 is cleared here */
+ 0x28, 0xE1, /* Set the FIFCrst bit here */
+ 0x28, 0xE0, /* Clear the FIFCrst bit here */
+ 0x00
+};
+
+/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
+static const u8 MT2063B3_defaults[] = {
+ /* Reg, Value */
+ 0x05, 0xF0,
+ 0x19, 0x3D,
+ 0x2C, 0x24, /* bit at 0x20 is cleared below */
+ 0x2C, 0x04, /* bit at 0x20 is cleared here */
+ 0x28, 0xE1, /* Set the FIFCrst bit here */
+ 0x28, 0xE0, /* Clear the FIFCrst bit here */
+ 0x00
+};
+
+static int mt2063_init(struct dvb_frontend *fe)
+{
+ u32 status;
+ struct mt2063_state *state = fe->tuner_priv;
+ u8 all_resets = 0xF0; /* reset/load bits */
+ const u8 *def = NULL;
+ char *step;
+ u32 FCRUN;
+ s32 maxReads;
+ u32 fcu_osc;
+ u32 i;
+
+ dprintk(2, "\n");
+
+ state->rcvr_mode = MT2063_CABLE_QAM;
+
+ /* Read the Part/Rev code from the tuner */
+ status = mt2063_read(state, MT2063_REG_PART_REV,
+ &state->reg[MT2063_REG_PART_REV], 1);
+ if (status < 0) {
+ printk(KERN_ERR "Can't read mt2063 part ID\n");
+ return status;
+ }
+
+ /* Check the part/rev code */
+ switch (state->reg[MT2063_REG_PART_REV]) {
+ case MT2063_B0:
+ step = "B0";
+ break;
+ case MT2063_B1:
+ step = "B1";
+ break;
+ case MT2063_B2:
+ step = "B2";
+ break;
+ case MT2063_B3:
+ step = "B3";
+ break;
+ default:
+ printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n",
+ state->reg[MT2063_REG_PART_REV]);
+ return -ENODEV; /* Wrong tuner Part/Rev code */
+ }
+
+ /* Check the 2nd byte of the Part/Rev code from the tuner */
+ status = mt2063_read(state, MT2063_REG_RSVD_3B,
+ &state->reg[MT2063_REG_RSVD_3B], 1);
+
+ /* b7 != 0 ==> NOT MT2063 */
+ if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) {
+ printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n",
+ state->reg[MT2063_REG_PART_REV],
+ state->reg[MT2063_REG_RSVD_3B]);
+ return -ENODEV; /* Wrong tuner Part/Rev code */
+ }
+
+ printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step);
+
+ /* Reset the tuner */
+ status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
+ if (status < 0)
+ return status;
+
+ /* change all of the default values that vary from the HW reset values */
+ /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
+ switch (state->reg[MT2063_REG_PART_REV]) {
+ case MT2063_B3:
+ def = MT2063B3_defaults;
+ break;
+
+ case MT2063_B1:
+ def = MT2063B1_defaults;
+ break;
+
+ case MT2063_B0:
+ def = MT2063B0_defaults;
+ break;
+
+ default:
+ return -ENODEV;
+ break;
+ }
+
+ while (status >= 0 && *def) {
+ u8 reg = *def++;
+ u8 val = *def++;
+ status = mt2063_write(state, reg, &val, 1);
+ }
+ if (status < 0)
+ return status;
+
+ /* Wait for FIFF location to complete. */
+ FCRUN = 1;
+ maxReads = 10;
+ while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
+ msleep(2);
+ status = mt2063_read(state,
+ MT2063_REG_XO_STATUS,
+ &state->
+ reg[MT2063_REG_XO_STATUS], 1);
+ FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
+ }
+
+ if (FCRUN != 0 || status < 0)
+ return -ENODEV;
+
+ status = mt2063_read(state,
+ MT2063_REG_FIFFC,
+ &state->reg[MT2063_REG_FIFFC], 1);
+ if (status < 0)
+ return status;
+
+ /* Read back all the registers from the tuner */
+ status = mt2063_read(state,
+ MT2063_REG_PART_REV,
+ state->reg, MT2063_REG_END_REGS);
+ if (status < 0)
+ return status;
+
+ /* Initialize the tuner state. */
+ state->tuner_id = state->reg[MT2063_REG_PART_REV];
+ state->AS_Data.f_ref = MT2063_REF_FREQ;
+ state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
+ ((u32) state->reg[MT2063_REG_FIFFC] + 640);
+ state->AS_Data.f_if1_bw = MT2063_IF1_BW;
+ state->AS_Data.f_out = 43750000UL;
+ state->AS_Data.f_out_bw = 6750000UL;
+ state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
+ state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
+ state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
+ state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
+ state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
+ state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
+ state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
+ state->AS_Data.f_LO1 = 2181000000UL;
+ state->AS_Data.f_LO2 = 1486249786UL;
+ state->f_IF1_actual = state->AS_Data.f_if1_Center;
+ state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
+ state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
+ state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
+ state->num_regs = MT2063_REG_END_REGS;
+ state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
+ state->ctfilt_sw = 0;
+
+ state->CTFiltMax[0] = 69230000;
+ state->CTFiltMax[1] = 105770000;
+ state->CTFiltMax[2] = 140350000;
+ state->CTFiltMax[3] = 177110000;
+ state->CTFiltMax[4] = 212860000;
+ state->CTFiltMax[5] = 241130000;
+ state->CTFiltMax[6] = 274370000;
+ state->CTFiltMax[7] = 309820000;
+ state->CTFiltMax[8] = 342450000;
+ state->CTFiltMax[9] = 378870000;
+ state->CTFiltMax[10] = 416210000;
+ state->CTFiltMax[11] = 456500000;
+ state->CTFiltMax[12] = 495790000;
+ state->CTFiltMax[13] = 534530000;
+ state->CTFiltMax[14] = 572610000;
+ state->CTFiltMax[15] = 598970000;
+ state->CTFiltMax[16] = 635910000;
+ state->CTFiltMax[17] = 672130000;
+ state->CTFiltMax[18] = 714840000;
+ state->CTFiltMax[19] = 739660000;
+ state->CTFiltMax[20] = 770410000;
+ state->CTFiltMax[21] = 814660000;
+ state->CTFiltMax[22] = 846950000;
+ state->CTFiltMax[23] = 867820000;
+ state->CTFiltMax[24] = 915980000;
+ state->CTFiltMax[25] = 947450000;
+ state->CTFiltMax[26] = 983110000;
+ state->CTFiltMax[27] = 1021630000;
+ state->CTFiltMax[28] = 1061870000;
+ state->CTFiltMax[29] = 1098330000;
+ state->CTFiltMax[30] = 1138990000;
+
+ /*
+ ** Fetch the FCU osc value and use it and the fRef value to
+ ** scale all of the Band Max values
+ */
+
+ state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
+ status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
+ &state->reg[MT2063_REG_CTUNE_CTRL], 1);
+ if (status < 0)
+ return status;
+
+ /* Read the ClearTune filter calibration value */
+ status = mt2063_read(state, MT2063_REG_FIFFC,
+ &state->reg[MT2063_REG_FIFFC], 1);
+ if (status < 0)
+ return status;
+
+ fcu_osc = state->reg[MT2063_REG_FIFFC];
+
+ state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
+ status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
+ &state->reg[MT2063_REG_CTUNE_CTRL], 1);
+ if (status < 0)
+ return status;
+
+ /* Adjust each of the values in the ClearTune filter cross-over table */
+ for (i = 0; i < 31; i++)
+ state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640);
+
+ status = MT2063_SoftwareShutdown(state, 1);
+ if (status < 0)
+ return status;
+ status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
+ if (status < 0)
+ return status;
+
+ state->init = true;
+
+ return 0;
+}
+
+static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status)
+{
+ struct mt2063_state *state = fe->tuner_priv;
+ int status;
+
+ dprintk(2, "\n");
+
+ if (!state->init)
+ return -ENODEV;
+
+ *tuner_status = 0;
+ status = mt2063_lockStatus(state);
+ if (status < 0)
+ return status;
+ if (status)
+ *tuner_status = TUNER_STATUS_LOCKED;
+
+ dprintk(1, "Tuner status: %d", *tuner_status);
+
+ return 0;
+}
+
+static int mt2063_release(struct dvb_frontend *fe)
+{
+ struct mt2063_state *state = fe->tuner_priv;
+
+ dprintk(2, "\n");
+
+ fe->tuner_priv = NULL;
+ kfree(state);
+
+ return 0;
+}
+
+static int mt2063_set_analog_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct mt2063_state *state = fe->tuner_priv;
+ s32 pict_car;
+ s32 pict2chanb_vsb;
+ s32 ch_bw;
+ s32 if_mid;
+ s32 rcvr_mode;
+ int status;
+
+ dprintk(2, "\n");
+
+ if (!state->init) {
+ status = mt2063_init(fe);
+ if (status < 0)
+ return status;
+ }
+
+ switch (params->mode) {
+ case V4L2_TUNER_RADIO:
+ pict_car = 38900000;
+ ch_bw = 8000000;
+ pict2chanb_vsb = -(ch_bw / 2);
+ rcvr_mode = MT2063_OFFAIR_ANALOG;
+ break;
+ case V4L2_TUNER_ANALOG_TV:
+ rcvr_mode = MT2063_CABLE_ANALOG;
+ if (params->std & ~V4L2_STD_MN) {
+ pict_car = 38900000;
+ ch_bw = 6000000;
+ pict2chanb_vsb = -1250000;
+ } else if (params->std & V4L2_STD_PAL_G) {
+ pict_car = 38900000;
+ ch_bw = 7000000;
+ pict2chanb_vsb = -1250000;
+ } else { /* PAL/SECAM standards */
+ pict_car = 38900000;
+ ch_bw = 8000000;
+ pict2chanb_vsb = -1250000;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
+
+ state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */
+ state->AS_Data.f_out = if_mid;
+ state->AS_Data.f_out_bw = ch_bw + 750000;
+ status = MT2063_SetReceiverMode(state, rcvr_mode);
+ if (status < 0)
+ return status;
+
+ dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n",
+ params->frequency, ch_bw, pict2chanb_vsb);
+
+ status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2))));
+ if (status < 0)
+ return status;
+
+ state->frequency = params->frequency;
+ return 0;
+}
+
+/*
+ * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
+ * So, the amount of the needed bandwith is given by:
+ * Bw = Symbol_rate * (1 + 0.15)
+ * As such, the maximum symbol rate supported by 6 MHz is given by:
+ * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
+ */
+#define MAX_SYMBOL_RATE_6MHz 5217391
+
+static int mt2063_set_params(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct mt2063_state *state = fe->tuner_priv;
+ int status;
+ s32 pict_car;
+ s32 pict2chanb_vsb;
+ s32 ch_bw;
+ s32 if_mid;
+ s32 rcvr_mode;
+
+ if (!state->init) {
+ status = mt2063_init(fe);
+ if (status < 0)
+ return status;
+ }
+
+ dprintk(2, "\n");
+
+ if (c->bandwidth_hz == 0)
+ return -EINVAL;
+ if (c->bandwidth_hz <= 6000000)
+ ch_bw = 6000000;
+ else if (c->bandwidth_hz <= 7000000)
+ ch_bw = 7000000;
+ else
+ ch_bw = 8000000;
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ rcvr_mode = MT2063_OFFAIR_COFDM;
+ pict_car = 36125000;
+ pict2chanb_vsb = -(ch_bw / 2);
+ break;
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
+ rcvr_mode = MT2063_CABLE_QAM;
+ pict_car = 36125000;
+ pict2chanb_vsb = -(ch_bw / 2);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
+
+ state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */
+ state->AS_Data.f_out = if_mid;
+ state->AS_Data.f_out_bw = ch_bw + 750000;
+ status = MT2063_SetReceiverMode(state, rcvr_mode);
+ if (status < 0)
+ return status;
+
+ dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n",
+ c->frequency, ch_bw, pict2chanb_vsb);
+
+ status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2))));
+
+ if (status < 0)
+ return status;
+
+ state->frequency = c->frequency;
+ return 0;
+}
+
+static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+ struct mt2063_state *state = fe->tuner_priv;
+
+ dprintk(2, "\n");
+
+ if (!state->init)
+ return -ENODEV;
+
+ *freq = state->AS_Data.f_out;
+
+ dprintk(1, "IF frequency: %d\n", *freq);
+
+ return 0;
+}
+
+static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+ struct mt2063_state *state = fe->tuner_priv;
+
+ dprintk(2, "\n");
+
+ if (!state->init)
+ return -ENODEV;
+
+ *bw = state->AS_Data.f_out_bw - 750000;
+
+ dprintk(1, "bandwidth: %d\n", *bw);
+
+ return 0;
+}
+
+static struct dvb_tuner_ops mt2063_ops = {
+ .info = {
+ .name = "MT2063 Silicon Tuner",
+ .frequency_min = 45000000,
+ .frequency_max = 865000000,
+ .frequency_step = 0,
+ },
+
+ .init = mt2063_init,
+ .sleep = MT2063_Sleep,
+ .get_status = mt2063_get_status,
+ .set_analog_params = mt2063_set_analog_params,
+ .set_params = mt2063_set_params,
+ .get_if_frequency = mt2063_get_if_frequency,
+ .get_bandwidth = mt2063_get_bandwidth,
+ .release = mt2063_release,
+};
+
+struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
+ struct mt2063_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct mt2063_state *state = NULL;
+
+ dprintk(2, "\n");
+
+ state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ state->config = config;
+ state->i2c = i2c;
+ state->frontend = fe;
+ state->reference = config->refclock / 1000; /* kHz */
+ fe->tuner_priv = state;
+ fe->ops.tuner_ops = mt2063_ops;
+
+ printk(KERN_INFO "%s: Attaching MT2063\n", __func__);
+ return fe;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(mt2063_attach);
+
+/*
+ * Ancillary routines visible outside mt2063
+ * FIXME: Remove them in favor of using standard tuner callbacks
+ */
+unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
+{
+ struct mt2063_state *state = fe->tuner_priv;
+ int err = 0;
+
+ dprintk(2, "\n");
+
+ err = MT2063_SoftwareShutdown(state, 1);
+ if (err < 0)
+ printk(KERN_ERR "%s: Couldn't shutdown\n", __func__);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown);
+
+unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
+{
+ struct mt2063_state *state = fe->tuner_priv;
+ int err = 0;
+
+ dprintk(2, "\n");
+
+ err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
+ if (err < 0)
+ printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits);
+
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("MT2063 Silicon tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mt2063.h b/drivers/media/common/tuners/mt2063.h
new file mode 100644
index 000000000000..3f5cfd93713f
--- /dev/null
+++ b/drivers/media/common/tuners/mt2063.h
@@ -0,0 +1,32 @@
+#ifndef __MT2063_H__
+#define __MT2063_H__
+
+#include "dvb_frontend.h"
+
+struct mt2063_config {
+ u8 tuner_address;
+ u32 refclock;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MT2063) || (defined(CONFIG_MEDIA_TUNER_MT2063_MODULE) && defined(MODULE))
+struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
+ struct mt2063_config *config,
+ struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
+ struct mt2063_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+
+/* FIXME: Should use the standard DVB attachment interfaces */
+unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe);
+unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe);
+
+#endif /* CONFIG_DVB_MT2063 */
+
+#endif /* __MT2063_H__ */
diff --git a/drivers/media/common/tuners/mt2131.c b/drivers/media/common/tuners/mt2131.c
index a4f830bb25d1..f83b0c1ea6c8 100644
--- a/drivers/media/common/tuners/mt2131.c
+++ b/drivers/media/common/tuners/mt2131.c
@@ -92,9 +92,9 @@ static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len)
return 0;
}
-static int mt2131_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int mt2131_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct mt2131_priv *priv;
int ret=0, i;
u32 freq;
@@ -105,12 +105,8 @@ static int mt2131_set_params(struct dvb_frontend *fe,
u8 lockval = 0;
priv = fe->tuner_priv;
- if (fe->ops.info.type == FE_OFDM)
- priv->bandwidth = params->u.ofdm.bandwidth;
- else
- priv->bandwidth = 0;
- freq = params->frequency / 1000; // Hz -> kHz
+ freq = c->frequency / 1000; /* Hz -> kHz */
dprintk(1, "%s() freq=%d\n", __func__, freq);
f_lo1 = freq + MT2131_IF1 * 1000;
@@ -193,14 +189,6 @@ static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
return 0;
}
-static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
- struct mt2131_priv *priv = fe->tuner_priv;
- dprintk(1, "%s()\n", __func__);
- *bandwidth = priv->bandwidth;
- return 0;
-}
-
static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)
{
struct mt2131_priv *priv = fe->tuner_priv;
@@ -263,7 +251,6 @@ static const struct dvb_tuner_ops mt2131_tuner_ops = {
.set_params = mt2131_set_params,
.get_frequency = mt2131_get_frequency,
- .get_bandwidth = mt2131_get_bandwidth,
.get_status = mt2131_get_status
};
@@ -281,7 +268,6 @@ struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe,
return NULL;
priv->cfg = cfg;
- priv->bandwidth = 6000000; /* 6MHz */
priv->i2c = i2c;
if (mt2131_readreg(priv, 0, &id) != 0) {
diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h
index 4e05a67e88c1..62aeedf5c550 100644
--- a/drivers/media/common/tuners/mt2131_priv.h
+++ b/drivers/media/common/tuners/mt2131_priv.h
@@ -38,7 +38,6 @@ struct mt2131_priv {
struct i2c_adapter *i2c;
u32 frequency;
- u32 bandwidth;
};
#endif /* __MT2131_PRIV_H__ */
diff --git a/drivers/media/common/tuners/mt2266.c b/drivers/media/common/tuners/mt2266.c
index 25a8ea342c46..bca4d75e42d4 100644
--- a/drivers/media/common/tuners/mt2266.c
+++ b/drivers/media/common/tuners/mt2266.c
@@ -122,8 +122,9 @@ static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
#define FREF 30000 // Quartz oscillator 30 MHz
-static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int mt2266_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct mt2266_priv *priv;
int ret=0;
u32 freq;
@@ -135,32 +136,32 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
priv = fe->tuner_priv;
- freq = params->frequency / 1000; // Hz -> kHz
+ freq = priv->frequency / 1000; /* Hz -> kHz */
if (freq < 470000 && freq > 230000)
return -EINVAL; /* Gap between VHF and UHF bands */
- priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
- priv->frequency = freq * 1000;
+ priv->frequency = c->frequency;
tune = 2 * freq * (8192/16) / (FREF/16);
band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
if (band == MT2266_VHF)
tune *= 2;
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (c->bandwidth_hz) {
+ case 6000000:
mt2266_writeregs(priv, mt2266_init_6mhz,
sizeof(mt2266_init_6mhz));
break;
- case BANDWIDTH_7_MHZ:
- mt2266_writeregs(priv, mt2266_init_7mhz,
- sizeof(mt2266_init_7mhz));
- break;
- case BANDWIDTH_8_MHZ:
- default:
+ case 8000000:
mt2266_writeregs(priv, mt2266_init_8mhz,
sizeof(mt2266_init_8mhz));
break;
+ case 7000000:
+ default:
+ mt2266_writeregs(priv, mt2266_init_7mhz,
+ sizeof(mt2266_init_7mhz));
+ break;
}
+ priv->bandwidth = c->bandwidth_hz;
if (band == MT2266_VHF && priv->band == MT2266_UHF) {
dprintk("Switch from UHF to VHF");
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
index 54be9e6faaaf..6133315fb0e3 100644
--- a/drivers/media/common/tuners/mxl5005s.c
+++ b/drivers/media/common/tuners/mxl5005s.c
@@ -3979,54 +3979,47 @@ static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type,
return 0;
}
-static int mxl5005s_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int mxl5005s_set_params(struct dvb_frontend *fe)
{
struct mxl5005s_state *state = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
+ u32 bw = c->bandwidth_hz;
u32 req_mode, req_bw = 0;
int ret;
dprintk(1, "%s()\n", __func__);
- if (fe->ops.info.type == FE_ATSC) {
- switch (params->u.vsb.modulation) {
- case VSB_8:
- req_mode = MXL_ATSC; break;
- default:
- case QAM_64:
- case QAM_256:
- case QAM_AUTO:
- req_mode = MXL_QAM; break;
- }
- } else
+ switch (delsys) {
+ case SYS_ATSC:
+ req_mode = MXL_ATSC;
+ req_bw = MXL5005S_BANDWIDTH_6MHZ;
+ break;
+ case SYS_DVBC_ANNEX_B:
+ req_mode = MXL_QAM;
+ req_bw = MXL5005S_BANDWIDTH_6MHZ;
+ break;
+ default: /* Assume DVB-T */
req_mode = MXL_DVBT;
-
- /* Change tuner for new modulation type if reqd */
- if (req_mode != state->current_mode) {
- switch (req_mode) {
- case MXL_ATSC:
- case MXL_QAM:
- req_bw = MXL5005S_BANDWIDTH_6MHZ;
+ switch (bw) {
+ case 6000000:
+ req_bw = MXL5005S_BANDWIDTH_6MHZ;
+ break;
+ case 7000000:
+ req_bw = MXL5005S_BANDWIDTH_7MHZ;
+ break;
+ case 8000000:
+ case 0:
+ req_bw = MXL5005S_BANDWIDTH_8MHZ;
break;
- case MXL_DVBT:
default:
- /* Assume DVB-T */
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
- req_bw = MXL5005S_BANDWIDTH_6MHZ;
- break;
- case BANDWIDTH_7_MHZ:
- req_bw = MXL5005S_BANDWIDTH_7MHZ;
- break;
- case BANDWIDTH_AUTO:
- case BANDWIDTH_8_MHZ:
- req_bw = MXL5005S_BANDWIDTH_8MHZ;
- break;
- default:
- return -EINVAL;
- }
+ return -EINVAL;
}
+ }
+ /* Change tuner for new modulation type if reqd */
+ if (req_mode != state->current_mode ||
+ req_bw != state->Chan_Bandwidth) {
state->current_mode = req_mode;
ret = mxl5005s_reconfigure(fe, req_mode, req_bw);
@@ -4034,8 +4027,8 @@ static int mxl5005s_set_params(struct dvb_frontend *fe,
ret = 0;
if (ret == 0) {
- dprintk(1, "%s() freq=%d\n", __func__, params->frequency);
- ret = mxl5005s_SetRfFreqHz(fe, params->frequency);
+ dprintk(1, "%s() freq=%d\n", __func__, c->frequency);
+ ret = mxl5005s_SetRfFreqHz(fe, c->frequency);
}
return ret;
diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c
index 5d02221e99dd..69e453ef0a1a 100644
--- a/drivers/media/common/tuners/mxl5007t.c
+++ b/drivers/media/common/tuners/mxl5007t.c
@@ -165,6 +165,8 @@ struct mxl5007t_state {
struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)];
struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)];
+ enum mxl5007t_if_freq if_freq;
+
u32 frequency;
u32 bandwidth;
};
@@ -286,6 +288,8 @@ static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state,
/* set inverted IF or normal IF */
set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00);
+ state->if_freq = if_freq;
+
return;
}
@@ -612,47 +616,43 @@ fail:
/* ------------------------------------------------------------------------- */
-static int mxl5007t_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int mxl5007t_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
struct mxl5007t_state *state = fe->tuner_priv;
enum mxl5007t_bw_mhz bw;
enum mxl5007t_mode mode;
int ret;
- u32 freq = params->frequency;
+ u32 freq = c->frequency;
- if (fe->ops.info.type == FE_ATSC) {
- switch (params->u.vsb.modulation) {
- case VSB_8:
- case VSB_16:
- mode = MxL_MODE_ATSC;
- break;
- case QAM_64:
- case QAM_256:
- mode = MxL_MODE_CABLE;
- break;
- default:
- mxl_err("modulation not set!");
- return -EINVAL;
- }
+ switch (delsys) {
+ case SYS_ATSC:
+ mode = MxL_MODE_ATSC;
+ bw = MxL_BW_6MHz;
+ break;
+ case SYS_DVBC_ANNEX_B:
+ mode = MxL_MODE_CABLE;
bw = MxL_BW_6MHz;
- } else if (fe->ops.info.type == FE_OFDM) {
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ break;
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ mode = MxL_MODE_DVBT;
+ switch (c->bandwidth_hz) {
+ case 6000000:
bw = MxL_BW_6MHz;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
bw = MxL_BW_7MHz;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
bw = MxL_BW_8MHz;
break;
default:
- mxl_err("bandwidth not set!");
return -EINVAL;
}
- mode = MxL_MODE_DVBT;
- } else {
+ break;
+ default:
mxl_err("modulation type not supported!");
return -EINVAL;
}
@@ -671,8 +671,7 @@ static int mxl5007t_set_params(struct dvb_frontend *fe,
goto fail;
state->frequency = freq;
- state->bandwidth = (fe->ops.info.type == FE_OFDM) ?
- params->u.ofdm.bandwidth : 0;
+ state->bandwidth = c->bandwidth_hz;
fail:
mutex_unlock(&state->lock);
@@ -738,6 +737,50 @@ static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
return 0;
}
+static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct mxl5007t_state *state = fe->tuner_priv;
+
+ *frequency = 0;
+
+ switch (state->if_freq) {
+ case MxL_IF_4_MHZ:
+ *frequency = 4000000;
+ break;
+ case MxL_IF_4_5_MHZ:
+ *frequency = 4500000;
+ break;
+ case MxL_IF_4_57_MHZ:
+ *frequency = 4570000;
+ break;
+ case MxL_IF_5_MHZ:
+ *frequency = 5000000;
+ break;
+ case MxL_IF_5_38_MHZ:
+ *frequency = 5380000;
+ break;
+ case MxL_IF_6_MHZ:
+ *frequency = 6000000;
+ break;
+ case MxL_IF_6_28_MHZ:
+ *frequency = 6280000;
+ break;
+ case MxL_IF_9_1915_MHZ:
+ *frequency = 9191500;
+ break;
+ case MxL_IF_35_25_MHZ:
+ *frequency = 35250000;
+ break;
+ case MxL_IF_36_15_MHZ:
+ *frequency = 36150000;
+ break;
+ case MxL_IF_44_MHZ:
+ *frequency = 44000000;
+ break;
+ }
+ return 0;
+}
+
static int mxl5007t_release(struct dvb_frontend *fe)
{
struct mxl5007t_state *state = fe->tuner_priv;
@@ -767,6 +810,7 @@ static struct dvb_tuner_ops mxl5007t_tuner_ops = {
.get_frequency = mxl5007t_get_frequency,
.get_bandwidth = mxl5007t_get_bandwidth,
.release = mxl5007t_release,
+ .get_if_frequency = mxl5007t_get_if_frequency,
};
static int mxl5007t_get_chip_id(struct mxl5007t_state *state)
diff --git a/drivers/media/common/tuners/qt1010.c b/drivers/media/common/tuners/qt1010.c
index 9f5dba244cb8..2d79b1f5d5eb 100644
--- a/drivers/media/common/tuners/qt1010.c
+++ b/drivers/media/common/tuners/qt1010.c
@@ -82,9 +82,9 @@ static void qt1010_dump_regs(struct qt1010_priv *priv)
printk(KERN_CONT "\n");
}
-static int qt1010_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int qt1010_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct qt1010_priv *priv;
int err;
u32 freq, div, mod1, mod2;
@@ -144,13 +144,11 @@ static int qt1010_set_params(struct dvb_frontend *fe,
#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */
priv = fe->tuner_priv;
- freq = params->frequency;
+ freq = c->frequency;
div = (freq + QT1010_OFFSET) / QT1010_STEP;
freq = (div * QT1010_STEP) - QT1010_OFFSET;
mod1 = (freq + QT1010_OFFSET) % FREQ1;
mod2 = (freq + QT1010_OFFSET) % FREQ2;
- priv->bandwidth =
- (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
priv->frequency = freq;
if (fe->ops.i2c_gate_ctrl)
@@ -320,7 +318,7 @@ static u8 qt1010_init_meas2(struct qt1010_priv *priv,
static int qt1010_init(struct dvb_frontend *fe)
{
struct qt1010_priv *priv = fe->tuner_priv;
- struct dvb_frontend_parameters params;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int err = 0;
u8 i, tmpval, *valptr = NULL;
@@ -397,9 +395,9 @@ static int qt1010_init(struct dvb_frontend *fe)
if ((err = qt1010_init_meas2(priv, i, &tmpval)))
return err;
- params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */
+ c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */
/* MSI Megasky 580 GL861 533000000 */
- return qt1010_set_params(fe, &params);
+ return qt1010_set_params(fe);
}
static int qt1010_release(struct dvb_frontend *fe)
@@ -416,10 +414,9 @@ static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
return 0;
}
-static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
- struct qt1010_priv *priv = fe->tuner_priv;
- *bandwidth = priv->bandwidth;
+ *frequency = 36125000;
return 0;
}
@@ -437,7 +434,7 @@ static const struct dvb_tuner_ops qt1010_tuner_ops = {
.set_params = qt1010_set_params,
.get_frequency = qt1010_get_frequency,
- .get_bandwidth = qt1010_get_bandwidth
+ .get_if_frequency = qt1010_get_if_frequency,
};
struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/common/tuners/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h
index 090cf475f099..2c42d3f01636 100644
--- a/drivers/media/common/tuners/qt1010_priv.h
+++ b/drivers/media/common/tuners/qt1010_priv.h
@@ -99,7 +99,6 @@ struct qt1010_priv {
u8 reg25_init_val;
u32 frequency;
- u32 bandwidth;
};
#endif
diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c
index e29cc2bc113a..602c2e392b17 100644
--- a/drivers/media/common/tuners/tda18212.c
+++ b/drivers/media/common/tuners/tda18212.c
@@ -25,6 +25,8 @@
struct tda18212_priv {
struct tda18212_config *cfg;
struct i2c_adapter *i2c;
+
+ u32 if_frequency;
};
#define dbg(fmt, arg...) \
@@ -128,20 +130,31 @@ static void tda18212_dump_regs(struct tda18212_priv *priv)
}
#endif
-static int tda18212_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int tda18212_set_params(struct dvb_frontend *fe)
{
struct tda18212_priv *priv = fe->tuner_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
u32 if_khz;
u8 buf[9];
+ #define DVBT_6 0
+ #define DVBT_7 1
+ #define DVBT_8 2
+ #define DVBT2_6 3
+ #define DVBT2_7 4
+ #define DVBT2_8 5
+ #define DVBC_6 6
+ #define DVBC_8 7
static const u8 bw_params[][3] = {
- /* 0f 13 23 */
- { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */
- { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */
- { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */
- { 0x92, 0x53, 0x03 }, /* DVB-C */
+ /* reg: 0f 13 23 */
+ [DVBT_6] = { 0xb3, 0x20, 0x03 },
+ [DVBT_7] = { 0xb3, 0x31, 0x01 },
+ [DVBT_8] = { 0xb3, 0x22, 0x01 },
+ [DVBT2_6] = { 0xbc, 0x20, 0x03 },
+ [DVBT2_7] = { 0xbc, 0x72, 0x03 },
+ [DVBT2_8] = { 0xbc, 0x22, 0x01 },
+ [DVBC_6] = { 0x92, 0x50, 0x03 },
+ [DVBC_8] = { 0x92, 0x53, 0x03 },
};
dbg("delsys=%d RF=%d BW=%d\n",
@@ -155,24 +168,44 @@ static int tda18212_set_params(struct dvb_frontend *fe,
switch (c->bandwidth_hz) {
case 6000000:
if_khz = priv->cfg->if_dvbt_6;
- i = 0;
+ i = DVBT_6;
break;
case 7000000:
if_khz = priv->cfg->if_dvbt_7;
- i = 1;
+ i = DVBT_7;
break;
case 8000000:
if_khz = priv->cfg->if_dvbt_8;
- i = 2;
+ i = DVBT_8;
break;
default:
ret = -EINVAL;
goto error;
}
break;
- case SYS_DVBC_ANNEX_AC:
+ case SYS_DVBT2:
+ switch (c->bandwidth_hz) {
+ case 6000000:
+ if_khz = priv->cfg->if_dvbt2_6;
+ i = DVBT2_6;
+ break;
+ case 7000000:
+ if_khz = priv->cfg->if_dvbt2_7;
+ i = DVBT2_7;
+ break;
+ case 8000000:
+ if_khz = priv->cfg->if_dvbt2_8;
+ i = DVBT2_8;
+ break;
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
+ break;
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
if_khz = priv->cfg->if_dvbc;
- i = 3;
+ i = DVBC_8;
break;
default:
ret = -EINVAL;
@@ -194,7 +227,7 @@ static int tda18212_set_params(struct dvb_frontend *fe,
buf[0] = 0x02;
buf[1] = bw_params[i][1];
buf[2] = 0x03; /* default value */
- buf[3] = if_khz / 50;
+ buf[3] = DIV_ROUND_CLOSEST(if_khz, 50);
buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
buf[5] = ((c->frequency / 1000) >> 8) & 0xff;
buf[6] = ((c->frequency / 1000) >> 0) & 0xff;
@@ -204,6 +237,9 @@ static int tda18212_set_params(struct dvb_frontend *fe,
if (ret)
goto error;
+ /* actual IF rounded as it is on register */
+ priv->if_frequency = buf[3] * 50 * 1000;
+
exit:
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
@@ -215,6 +251,15 @@ error:
goto exit;
}
+static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tda18212_priv *priv = fe->tuner_priv;
+
+ *frequency = priv->if_frequency;
+
+ return 0;
+}
+
static int tda18212_release(struct dvb_frontend *fe)
{
kfree(fe->tuner_priv);
@@ -234,6 +279,7 @@ static const struct dvb_tuner_ops tda18212_tuner_ops = {
.release = tda18212_release,
.set_params = tda18212_set_params,
+ .get_if_frequency = tda18212_get_if_frequency,
};
struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/common/tuners/tda18212.h b/drivers/media/common/tuners/tda18212.h
index 83b497f59e1b..9bd5da4aabb7 100644
--- a/drivers/media/common/tuners/tda18212.h
+++ b/drivers/media/common/tuners/tda18212.h
@@ -29,6 +29,10 @@ struct tda18212_config {
u16 if_dvbt_6;
u16 if_dvbt_7;
u16 if_dvbt_8;
+ u16 if_dvbt2_5;
+ u16 if_dvbt2_6;
+ u16 if_dvbt2_7;
+ u16 if_dvbt2_8;
u16 if_dvbc;
};
diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c
index 4fc29730a12c..dfb3a831df45 100644
--- a/drivers/media/common/tuners/tda18218.c
+++ b/drivers/media/common/tuners/tda18218.c
@@ -109,10 +109,11 @@ static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
return tda18218_rd_regs(priv, reg, val, 1);
}
-static int tda18218_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int tda18218_set_params(struct dvb_frontend *fe)
{
struct tda18218_priv *priv = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 bw = c->bandwidth_hz;
int ret;
u8 buf[3], i, BP_Filter, LP_Fc;
u32 LO_Frac;
@@ -138,22 +139,19 @@ static int tda18218_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
/* low-pass filter cut-off frequency */
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ if (bw <= 6000000) {
LP_Fc = 0;
- LO_Frac = params->frequency + 3000000;
- break;
- case BANDWIDTH_7_MHZ:
+ priv->if_frequency = 3000000;
+ } else if (bw <= 7000000) {
LP_Fc = 1;
- LO_Frac = params->frequency + 3500000;
- break;
- case BANDWIDTH_8_MHZ:
- default:
+ priv->if_frequency = 3500000;
+ } else {
LP_Fc = 2;
- LO_Frac = params->frequency + 4000000;
- break;
+ priv->if_frequency = 4000000;
}
+ LO_Frac = c->frequency + priv->if_frequency;
+
/* band-pass filter */
if (LO_Frac < 188000000)
BP_Filter = 3;
@@ -206,6 +204,14 @@ error:
return ret;
}
+static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ *frequency = priv->if_frequency;
+ dbg("%s: if=%d", __func__, *frequency);
+ return 0;
+}
+
static int tda18218_sleep(struct dvb_frontend *fe)
{
struct tda18218_priv *priv = fe->tuner_priv;
@@ -268,6 +274,8 @@ static const struct dvb_tuner_ops tda18218_tuner_ops = {
.sleep = tda18218_sleep,
.set_params = tda18218_set_params,
+
+ .get_if_frequency = tda18218_get_if_frequency,
};
struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/common/tuners/tda18218_priv.h b/drivers/media/common/tuners/tda18218_priv.h
index 904e5365c78c..dc52b72e1407 100644
--- a/drivers/media/common/tuners/tda18218_priv.h
+++ b/drivers/media/common/tuners/tda18218_priv.h
@@ -100,6 +100,8 @@ struct tda18218_priv {
struct tda18218_config *cfg;
struct i2c_adapter *i2c;
+ u32 if_frequency;
+
u8 regs[TDA18218_NUM_REGS];
};
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index 63cc4004e211..2e67f4459904 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -928,59 +928,49 @@ fail:
/* ------------------------------------------------------------------ */
-static int tda18271_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int tda18271_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
+ u32 bw = c->bandwidth_hz;
+ u32 freq = c->frequency;
struct tda18271_priv *priv = fe->tuner_priv;
struct tda18271_std_map *std_map = &priv->std;
struct tda18271_std_map_item *map;
int ret;
- u32 bw, freq = params->frequency;
priv->mode = TDA18271_DIGITAL;
- if (fe->ops.info.type == FE_ATSC) {
- switch (params->u.vsb.modulation) {
- case VSB_8:
- case VSB_16:
- map = &std_map->atsc_6;
- break;
- case QAM_64:
- case QAM_256:
- map = &std_map->qam_6;
- break;
- default:
- tda_warn("modulation not set!\n");
- return -EINVAL;
- }
-#if 0
- /* userspace request is already center adjusted */
- freq += 1750000; /* Adjust to center (+1.75MHZ) */
-#endif
+ switch (delsys) {
+ case SYS_ATSC:
+ map = &std_map->atsc_6;
bw = 6000000;
- } else if (fe->ops.info.type == FE_OFDM) {
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
- bw = 6000000;
+ break;
+ case SYS_ISDBT:
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ if (bw <= 6000000) {
map = &std_map->dvbt_6;
- break;
- case BANDWIDTH_7_MHZ:
- bw = 7000000;
+ } else if (bw <= 7000000) {
map = &std_map->dvbt_7;
- break;
- case BANDWIDTH_8_MHZ:
- bw = 8000000;
+ } else {
map = &std_map->dvbt_8;
- break;
- default:
- tda_warn("bandwidth not set!\n");
- return -EINVAL;
}
- } else if (fe->ops.info.type == FE_QAM) {
- /* DVB-C */
- map = &std_map->qam_8;
- bw = 8000000;
- } else {
+ break;
+ case SYS_DVBC_ANNEX_B:
+ bw = 6000000;
+ /* falltrough */
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
+ if (bw <= 6000000) {
+ map = &std_map->qam_6;
+ } else if (bw <= 7000000) {
+ map = &std_map->qam_7;
+ } else {
+ map = &std_map->qam_8;
+ }
+ break;
+ default:
tda_warn("modulation type not supported!\n");
return -EINVAL;
}
@@ -994,9 +984,9 @@ static int tda18271_set_params(struct dvb_frontend *fe,
if (tda_fail(ret))
goto fail;
+ priv->if_freq = map->if_freq;
priv->frequency = freq;
- priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
- params->u.ofdm.bandwidth : 0;
+ priv->bandwidth = bw;
fail:
return ret;
}
@@ -1050,6 +1040,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe,
if (tda_fail(ret))
goto fail;
+ priv->if_freq = map->if_freq;
priv->frequency = freq;
priv->bandwidth = 0;
fail:
@@ -1086,6 +1077,13 @@ static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
return 0;
}
+static int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tda18271_priv *priv = fe->tuner_priv;
+ *frequency = (u32)priv->if_freq * 1000;
+ return 0;
+}
+
/* ------------------------------------------------------------------ */
#define tda18271_update_std(std_cfg, name) do { \
@@ -1245,6 +1243,7 @@ static const struct dvb_tuner_ops tda18271_tuner_ops = {
.set_config = tda18271_set_config,
.get_frequency = tda18271_get_frequency,
.get_bandwidth = tda18271_get_bandwidth,
+ .get_if_frequency = tda18271_get_if_frequency,
};
struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c
index 3d5b6ab7e332..fb881c667c94 100644
--- a/drivers/media/common/tuners/tda18271-maps.c
+++ b/drivers/media/common/tuners/tda18271-maps.c
@@ -1213,6 +1213,8 @@ static struct tda18271_std_map tda18271c1_std_map = {
.if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
.qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
.if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+ .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
.qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
.if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
};
@@ -1244,6 +1246,8 @@ static struct tda18271_std_map tda18271c2_std_map = {
.if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
.qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
.if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+ .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
.qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
.if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
};
diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h
index 94340f47562b..454c152ccaa0 100644
--- a/drivers/media/common/tuners/tda18271-priv.h
+++ b/drivers/media/common/tuners/tda18271-priv.h
@@ -122,6 +122,8 @@ struct tda18271_priv {
struct mutex lock;
+ u16 if_freq;
+
u32 frequency;
u32 bandwidth;
};
diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h
index 50cfa8cebb93..640bae4e6a5a 100644
--- a/drivers/media/common/tuners/tda18271.h
+++ b/drivers/media/common/tuners/tda18271.h
@@ -53,6 +53,7 @@ struct tda18271_std_map {
struct tda18271_std_map_item dvbt_7;
struct tda18271_std_map_item dvbt_8;
struct tda18271_std_map_item qam_6;
+ struct tda18271_std_map_item qam_7;
struct tda18271_std_map_item qam_8;
};
diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c
index e0d5b43772b8..a0d176267470 100644
--- a/drivers/media/common/tuners/tda827x.c
+++ b/drivers/media/common/tuners/tda827x.c
@@ -152,9 +152,9 @@ static int tuner_transfer(struct dvb_frontend *fe,
return rc;
}
-static int tda827xo_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int tda827xo_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct tda827x_priv *priv = fe->tuner_priv;
u8 buf[14];
int rc;
@@ -165,18 +165,16 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
u32 N;
dprintk("%s:\n", __func__);
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ if (c->bandwidth_hz == 0) {
+ if_freq = 5000000;
+ } else if (c->bandwidth_hz <= 6000000) {
if_freq = 4000000;
- break;
- case BANDWIDTH_7_MHZ:
+ } else if (c->bandwidth_hz <= 7000000) {
if_freq = 4500000;
- break;
- default: /* 8 MHz or Auto */
+ } else { /* 8 MHz */
if_freq = 5000000;
- break;
}
- tuner_freq = params->frequency;
+ tuner_freq = c->frequency;
i = 0;
while (tda827x_table[i].lomax < tuner_freq) {
@@ -220,8 +218,8 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
if (rc < 0)
goto err;
- priv->frequency = params->frequency;
- priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+ priv->frequency = c->frequency;
+ priv->bandwidth = c->bandwidth_hz;
return 0;
@@ -513,9 +511,9 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
}
}
-static int tda827xa_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int tda827xa_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct tda827x_priv *priv = fe->tuner_priv;
struct tda827xa_data *frequency_map = tda827xa_dvbt;
u8 buf[11];
@@ -531,22 +529,25 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
tda827xa_lna_gain(fe, 1, NULL);
msleep(20);
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ if (c->bandwidth_hz == 0) {
+ if_freq = 5000000;
+ } else if (c->bandwidth_hz <= 6000000) {
if_freq = 4000000;
- break;
- case BANDWIDTH_7_MHZ:
+ } else if (c->bandwidth_hz <= 7000000) {
if_freq = 4500000;
- break;
- default: /* 8 MHz or Auto */
+ } else { /* 8 MHz */
if_freq = 5000000;
- break;
}
- tuner_freq = params->frequency;
+ tuner_freq = c->frequency;
- if (fe->ops.info.type == FE_QAM) {
+ switch (c->delivery_system) {
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
dprintk("%s select tda827xa_dvbc\n", __func__);
frequency_map = tda827xa_dvbc;
+ break;
+ default:
+ break;
}
i = 0;
@@ -645,9 +646,8 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
if (rc < 0)
goto err;
- priv->frequency = params->frequency;
- priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
-
+ priv->frequency = c->frequency;
+ priv->bandwidth = c->bandwidth_hz;
return 0;
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index f8ee29e6059c..39e7e583c8c0 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
@@ -751,6 +751,17 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
if (4 != rc)
tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
+ /* Write AUX byte */
+ switch (priv->type) {
+ case TUNER_PHILIPS_FM1216ME_MK3:
+ buffer[2] = 0x98;
+ buffer[3] = 0x20; /* set TOP AGC */
+ rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+ if (4 != rc)
+ tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
+ break;
+ }
+
return 0;
}
@@ -780,24 +791,26 @@ static int simple_set_params(struct dvb_frontend *fe,
}
static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
+ const u32 delsys,
+ const u32 frequency,
+ const u32 bandwidth)
{
struct tuner_simple_priv *priv = fe->tuner_priv;
switch (priv->type) {
case TUNER_PHILIPS_FMD1216ME_MK3:
case TUNER_PHILIPS_FMD1216MEX_MK3:
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
- params->frequency >= 158870000)
+ if (bandwidth == 8000000 &&
+ frequency >= 158870000)
buf[3] |= 0x08;
break;
case TUNER_PHILIPS_TD1316:
/* determine band */
- buf[3] |= (params->frequency < 161000000) ? 1 :
- (params->frequency < 444000000) ? 2 : 4;
+ buf[3] |= (frequency < 161000000) ? 1 :
+ (frequency < 444000000) ? 2 : 4;
/* setup PLL filter */
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+ if (bandwidth == 8000000)
buf[3] |= 1 << 3;
break;
case TUNER_PHILIPS_TUV1236D:
@@ -808,12 +821,11 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
if (dtv_input[priv->nr])
new_rf = dtv_input[priv->nr];
else
- switch (params->u.vsb.modulation) {
- case QAM_64:
- case QAM_256:
+ switch (delsys) {
+ case SYS_DVBC_ANNEX_B:
new_rf = 1;
break;
- case VSB_8:
+ case SYS_ATSC:
default:
new_rf = 0;
break;
@@ -827,7 +839,9 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
}
static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
+ const u32 delsys,
+ const u32 freq,
+ const u32 bw)
{
/* This function returns the tuned frequency on success, 0 on error */
struct tuner_simple_priv *priv = fe->tuner_priv;
@@ -836,7 +850,7 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
u8 config, cb;
u32 div;
int ret;
- unsigned frequency = params->frequency / 62500;
+ u32 frequency = freq / 62500;
if (!tun->stepsize) {
/* tuner-core was loaded before the digital tuner was
@@ -860,7 +874,7 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
buf[2] = config;
buf[3] = cb;
- simple_set_dvb(fe, buf, params);
+ simple_set_dvb(fe, buf, delsys, freq, bw);
tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
tun->name, div, buf[0], buf[1], buf[2], buf[3]);
@@ -870,32 +884,37 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
}
static int simple_dvb_calc_regs(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
u8 *buf, int buf_len)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
+ u32 bw = c->bandwidth_hz;
struct tuner_simple_priv *priv = fe->tuner_priv;
u32 frequency;
if (buf_len < 5)
return -EINVAL;
- frequency = simple_dvb_configure(fe, buf+1, params);
+ frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw);
if (frequency == 0)
return -EINVAL;
buf[0] = priv->i2c_props.addr;
priv->frequency = frequency;
- priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
- params->u.ofdm.bandwidth : 0;
+ priv->bandwidth = c->bandwidth_hz;
return 5;
}
-static int simple_dvb_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int simple_dvb_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
+ u32 bw = c->bandwidth_hz;
+ u32 freq = c->frequency;
struct tuner_simple_priv *priv = fe->tuner_priv;
+ u32 frequency;
u32 prev_freq, prev_bw;
int ret;
u8 buf[5];
@@ -906,9 +925,14 @@ static int simple_dvb_set_params(struct dvb_frontend *fe,
prev_freq = priv->frequency;
prev_bw = priv->bandwidth;
- ret = simple_dvb_calc_regs(fe, params, buf, 5);
- if (ret != 5)
- goto fail;
+ frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw);
+ if (frequency == 0)
+ return -EINVAL;
+
+ buf[0] = priv->i2c_props.addr;
+
+ priv->frequency = frequency;
+ priv->bandwidth = bw;
/* put analog demod in standby when tuning digital */
if (fe->ops.analog_ops.standby)
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
index e13683bab6b3..2da4440c16ee 100644
--- a/drivers/media/common/tuners/tuner-types.c
+++ b/drivers/media/common/tuners/tuner-types.c
@@ -1868,6 +1868,10 @@ struct tunertype tuners[] = {
.params = tuner_tena_tnf_5337_params,
.count = ARRAY_SIZE(tuner_tena_tnf_5337_params),
},
+ [TUNER_XC5000C] = { /* Xceive 5000C */
+ .name = "Xceive 5000C tuner",
+ /* see xc5000.c for details */
+ },
};
EXPORT_SYMBOL(tuners);
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
index 3acbaa04e1b3..b5ee3ebfcfca 100644
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
@@ -24,6 +24,21 @@
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
+/* Registers (Write-only) */
+#define XREG_INIT 0x00
+#define XREG_RF_FREQ 0x02
+#define XREG_POWER_DOWN 0x08
+
+/* Registers (Read-only) */
+#define XREG_FREQ_ERROR 0x01
+#define XREG_LOCK 0x02
+#define XREG_VERSION 0x04
+#define XREG_PRODUCT_ID 0x08
+#define XREG_HSYNC_FREQ 0x10
+#define XREG_FRAME_LINES 0x20
+#define XREG_SNR 0x40
+
+#define XREG_ADC_ENV 0x0100
static int debug;
module_param(debug, int, 0644);
@@ -311,7 +326,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
n_array, fname, name,
priv->firm_version >> 8, priv->firm_version & 0xff);
- priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
+ priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
if (priv->firm == NULL) {
tuner_err("Not enough memory to load firmware file.\n");
rc = -ENOMEM;
@@ -885,16 +900,16 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
mutex_lock(&priv->lock);
/* Sync Lock Indicator */
- rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
+ rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
if (rc < 0)
goto ret;
/* Frequency is locked */
if (frq_lock == 1)
- signal = 32768;
+ signal = 1 << 11;
/* Get SNR of the video signal */
- rc = xc2028_get_reg(priv, 0x0040, &signal);
+ rc = xc2028_get_reg(priv, XREG_SNR, &signal);
if (rc < 0)
goto ret;
@@ -962,14 +977,24 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
* For DTV 7/8, the firmware uses BW = 8000, so it needs a
* further adjustment to get the frequency center on VHF
*/
+
+ /*
+ * The firmware DTV78 used to work fine in UHF band (8 MHz
+ * bandwidth) but not at all in VHF band (7 MHz bandwidth).
+ * The real problem was connected to the formula used to
+ * calculate the center frequency offset in VHF band.
+ * In fact, removing the 500KHz adjustment fixed the problem.
+ * This is coherent to what was implemented for the DTV7
+ * firmware.
+ * In the end, now the center frequency is the same for all 3
+ * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel
+ * bandwidth.
+ */
+
if (priv->cur_fw.type & DTV6)
offset = 1750000;
- else if (priv->cur_fw.type & DTV7)
- offset = 2250000;
- else /* DTV8 or DTV78 */
+ else /* DTV7 or DTV8 or DTV78 */
offset = 2750000;
- if ((priv->cur_fw.type & DTV78) && freq < 470000000)
- offset -= 500000;
/*
* xc3028 additional "magic"
@@ -979,17 +1004,13 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
* newer firmwares
*/
-#if 1
/*
* The proper adjustment would be to do it at s-code table.
* However, this didn't work, as reported by
* Robert Lowery <rglowery@exemail.com.au>
*/
- if (priv->cur_fw.type & DTV7)
- offset += 500000;
-
-#else
+#if 0
/*
* Still need tests for XC3028L (firmware 3.2 or upper)
* So, for now, let's just comment the per-firmware
@@ -1013,9 +1034,9 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
/* CMD= Set frequency */
if (priv->firm_version < 0x0202)
- rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00});
+ rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00});
else
- rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00});
+ rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00});
if (rc < 0)
goto ret;
@@ -1084,68 +1105,28 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
V4L2_TUNER_ANALOG_TV, type, p->std, 0);
}
-static int xc2028_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int xc2028_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
+ u32 bw = c->bandwidth_hz;
struct xc2028_data *priv = fe->tuner_priv;
unsigned int type=0;
- fe_bandwidth_t bw = BANDWIDTH_8_MHZ;
u16 demod = 0;
tuner_dbg("%s called\n", __func__);
- switch(fe->ops.info.type) {
- case FE_OFDM:
- bw = p->u.ofdm.bandwidth;
+ switch (delsys) {
+ case SYS_DVBT:
+ case SYS_DVBT2:
/*
* 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)
+ if (bw <= 6000000)
type |= QAM;
- break;
- case FE_ATSC:
- bw = BANDWIDTH_6_MHZ;
- /* The only ATSC firmware (at least on v2.7) is D2633 */
- type |= ATSC | D2633;
- break;
- /* DVB-S and pure QAM (FE_QAM) are not supported */
- default:
- return -EINVAL;
- }
-
- switch (bw) {
- case BANDWIDTH_8_MHZ:
- if (p->frequency < 470000000)
- priv->ctrl.vhfbw7 = 0;
- else
- priv->ctrl.uhfbw8 = 1;
- type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
- type |= F8MHZ;
- break;
- case BANDWIDTH_7_MHZ:
- if (p->frequency < 470000000)
- priv->ctrl.vhfbw7 = 1;
- else
- priv->ctrl.uhfbw8 = 0;
- type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
- type |= F8MHZ;
- break;
- case BANDWIDTH_6_MHZ:
- type |= DTV6;
- priv->ctrl.vhfbw7 = 0;
- priv->ctrl.uhfbw8 = 0;
- break;
- default:
- tuner_err("error: bandwidth not supported.\n");
- };
- /*
- Selects between D2633 or D2620 firmware.
- It doesn't make sense for ATSC, since it should be D2633 on all cases
- */
- if (fe->ops.info.type != FE_ATSC) {
switch (priv->ctrl.type) {
case XC2028_D2633:
type |= D2633;
@@ -1161,6 +1142,34 @@ static int xc2028_set_params(struct dvb_frontend *fe,
else
type |= D2620;
}
+ break;
+ case SYS_ATSC:
+ /* The only ATSC firmware (at least on v2.7) is D2633 */
+ type |= ATSC | D2633;
+ break;
+ /* DVB-S and pure QAM (FE_QAM) are not supported */
+ default:
+ return -EINVAL;
+ }
+
+ if (bw <= 6000000) {
+ type |= DTV6;
+ priv->ctrl.vhfbw7 = 0;
+ priv->ctrl.uhfbw8 = 0;
+ } else if (bw <= 7000000) {
+ if (c->frequency < 470000000)
+ priv->ctrl.vhfbw7 = 1;
+ else
+ priv->ctrl.uhfbw8 = 0;
+ type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
+ type |= F8MHZ;
+ } else {
+ if (c->frequency < 470000000)
+ priv->ctrl.vhfbw7 = 0;
+ else
+ priv->ctrl.uhfbw8 = 1;
+ type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
+ type |= F8MHZ;
}
/* All S-code tables need a 200kHz shift */
@@ -1185,7 +1194,7 @@ static int xc2028_set_params(struct dvb_frontend *fe,
*/
}
- return generic_set_freq(fe, p->frequency,
+ return generic_set_freq(fe, c->frequency,
V4L2_TUNER_DIGITAL_TV, type, 0, demod);
}
@@ -1207,9 +1216,9 @@ static int xc2028_sleep(struct dvb_frontend *fe)
mutex_lock(&priv->lock);
if (priv->firm_version < 0x0202)
- rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
+ rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00});
else
- rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
+ rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00});
priv->cur_fw.type = 0; /* need firmware reload */
diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c
index 634f4d9b6c63..68397110b7d9 100644
--- a/drivers/media/common/tuners/xc4000.c
+++ b/drivers/media/common/tuners/xc4000.c
@@ -154,6 +154,8 @@ struct xc4000_priv {
#define XREG_SNR 0x06
#define XREG_VERSION 0x07
#define XREG_PRODUCT_ID 0x08
+#define XREG_SIGNAL_LEVEL 0x0A
+#define XREG_NOISE_LEVEL 0x0B
/*
Basic firmware description. This will remain with
@@ -486,6 +488,16 @@ static int xc_get_quality(struct xc4000_priv *priv, u16 *quality)
return xc4000_readreg(priv, XREG_QUALITY, quality);
}
+static int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal)
+{
+ return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal);
+}
+
+static int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise)
+{
+ return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise);
+}
+
static u16 xc_wait_for_lock(struct xc4000_priv *priv)
{
u16 lock_state = 0;
@@ -758,7 +770,7 @@ static int xc4000_fwupload(struct dvb_frontend *fe)
n_array, fname, name,
priv->firm_version >> 8, priv->firm_version & 0xff);
- priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
+ priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
if (priv->firm == NULL) {
printk(KERN_ERR "Not enough memory to load firmware file.\n");
rc = -ENOMEM;
@@ -1089,6 +1101,8 @@ static void xc_debug_dump(struct xc4000_priv *priv)
u32 hsync_freq_hz = 0;
u16 frame_lines;
u16 quality;
+ u16 signal = 0;
+ u16 noise = 0;
u8 hw_majorversion = 0, hw_minorversion = 0;
u8 fw_majorversion = 0, fw_minorversion = 0;
@@ -1119,85 +1133,70 @@ static void xc_debug_dump(struct xc4000_priv *priv)
xc_get_quality(priv, &quality);
dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+
+ xc_get_signal_level(priv, &signal);
+ dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal);
+
+ xc_get_noise_level(priv, &noise);
+ dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise);
}
-static int xc4000_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int xc4000_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
+ u32 bw = c->bandwidth_hz;
struct xc4000_priv *priv = fe->tuner_priv;
unsigned int type;
int ret = -EREMOTEIO;
- dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
+ dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency);
mutex_lock(&priv->lock);
- 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 = XC4000_DTV6;
- type = 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 = XC4000_DTV6;
- type = DTV6;
- break;
- default:
- ret = -EINVAL;
- goto fail;
- }
- } else if (fe->ops.info.type == FE_OFDM) {
+ switch (delsys) {
+ case SYS_ATSC:
+ dprintk(1, "%s() VSB modulation\n", __func__);
+ priv->rf_mode = XC_RF_MODE_AIR;
+ priv->freq_hz = c->frequency - 1750000;
+ priv->video_standard = XC4000_DTV6;
+ type = DTV6;
+ break;
+ case SYS_DVBC_ANNEX_B:
+ dprintk(1, "%s() QAM modulation\n", __func__);
+ priv->rf_mode = XC_RF_MODE_CABLE;
+ priv->freq_hz = c->frequency - 1750000;
+ priv->video_standard = XC4000_DTV6;
+ type = DTV6;
+ break;
+ case SYS_DVBT:
+ case SYS_DVBT2:
dprintk(1, "%s() OFDM\n", __func__);
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
- priv->bandwidth = BANDWIDTH_6_MHZ;
+ if (bw == 0) {
+ if (c->frequency < 400000000) {
+ priv->freq_hz = c->frequency - 2250000;
+ } else {
+ priv->freq_hz = c->frequency - 2750000;
+ }
+ priv->video_standard = XC4000_DTV7_8;
+ type = DTV78;
+ } else if (bw <= 6000000) {
priv->video_standard = XC4000_DTV6;
- priv->freq_hz = params->frequency - 1750000;
+ priv->freq_hz = c->frequency - 1750000;
type = DTV6;
- break;
- case BANDWIDTH_7_MHZ:
- priv->bandwidth = BANDWIDTH_7_MHZ;
+ } else if (bw <= 7000000) {
priv->video_standard = XC4000_DTV7;
- priv->freq_hz = params->frequency - 2250000;
+ priv->freq_hz = c->frequency - 2250000;
type = DTV7;
- break;
- case BANDWIDTH_8_MHZ:
- priv->bandwidth = BANDWIDTH_8_MHZ;
+ } else {
priv->video_standard = XC4000_DTV8;
- priv->freq_hz = params->frequency - 2750000;
+ priv->freq_hz = c->frequency - 2750000;
type = DTV8;
- break;
- case BANDWIDTH_AUTO:
- if (params->frequency < 400000000) {
- priv->bandwidth = BANDWIDTH_7_MHZ;
- priv->freq_hz = params->frequency - 2250000;
- } else {
- priv->bandwidth = BANDWIDTH_8_MHZ;
- priv->freq_hz = params->frequency - 2750000;
- }
- priv->video_standard = XC4000_DTV7_8;
- type = DTV78;
- break;
- default:
- printk(KERN_ERR "xc4000 bandwidth not set!\n");
- ret = -EINVAL;
- goto fail;
}
priv->rf_mode = XC_RF_MODE_AIR;
- } else {
- printk(KERN_ERR "xc4000 modulation type not supported!\n");
+ break;
+ default:
+ printk(KERN_ERR "xc4000 delivery system not supported!\n");
ret = -EINVAL;
goto fail;
}
@@ -1209,6 +1208,8 @@ static int xc4000_set_params(struct dvb_frontend *fe,
if (check_firmware(fe, type, 0, priv->if_khz) != 0)
goto fail;
+ priv->bandwidth = c->bandwidth_hz;
+
ret = xc_set_signal_source(priv, priv->rf_mode);
if (ret != 0) {
printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n",
@@ -1451,6 +1452,71 @@ fail:
return ret;
}
+static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ u16 value = 0;
+ int rc;
+
+ mutex_lock(&priv->lock);
+ rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value);
+ mutex_unlock(&priv->lock);
+
+ if (rc < 0)
+ goto ret;
+
+ /* Informations from real testing of DVB-T and radio part,
+ coeficient for one dB is 0xff.
+ */
+ tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value);
+
+ /* all known digital modes */
+ if ((priv->video_standard == XC4000_DTV6) ||
+ (priv->video_standard == XC4000_DTV7) ||
+ (priv->video_standard == XC4000_DTV7_8) ||
+ (priv->video_standard == XC4000_DTV8))
+ goto digital;
+
+ /* Analog mode has NOISE LEVEL important, signal
+ depends only on gain of antenna and amplifiers,
+ but it doesn't tell anything about real quality
+ of reception.
+ */
+ mutex_lock(&priv->lock);
+ rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value);
+ mutex_unlock(&priv->lock);
+
+ tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value);
+
+ /* highest noise level: 32dB */
+ if (value >= 0x2000) {
+ value = 0;
+ } else {
+ value = ~value << 3;
+ }
+
+ goto ret;
+
+ /* Digital mode has SIGNAL LEVEL important and real
+ noise level is stored in demodulator registers.
+ */
+digital:
+ /* best signal: -50dB */
+ if (value <= 0x3200) {
+ value = 0xffff;
+ /* minimum: -114dB - should be 0x7200 but real zero is 0x713A */
+ } else if (value >= 0x713A) {
+ value = 0;
+ } else {
+ value = ~(value - 0x3200) << 2;
+ }
+
+ret:
+ *strength = value;
+
+ return rc;
+}
+
static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq)
{
struct xc4000_priv *priv = fe->tuner_priv;
@@ -1578,6 +1644,7 @@ static const struct dvb_tuner_ops xc4000_tuner_ops = {
.set_params = xc4000_set_params,
.set_analog_params = xc4000_set_analog_params,
.get_frequency = xc4000_get_frequency,
+ .get_rf_strength = xc4000_get_signal,
.get_bandwidth = xc4000_get_bandwidth,
.get_status = xc4000_get_status
};
@@ -1605,7 +1672,7 @@ struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
break;
case 1:
/* new tuner instance */
- priv->bandwidth = BANDWIDTH_6_MHZ;
+ priv->bandwidth = 6000000;
/* set default configuration */
priv->if_khz = 4560;
priv->default_pm = 0;
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index aa1b2e844d32..7f98984e4fad 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -49,9 +49,6 @@ static LIST_HEAD(hybrid_tuner_instance_list);
#define dprintk(level, fmt, arg...) if (debug >= level) \
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
-#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
-#define XC5000_DEFAULT_FIRMWARE_SIZE 12401
-
struct xc5000_priv {
struct tuner_i2c_props i2c_props;
struct list_head hybrid_tuner_instance_list;
@@ -62,6 +59,8 @@ struct xc5000_priv {
u8 video_standard;
u8 rf_mode;
u8 radio_input;
+
+ int chip_id;
};
/* Misc Defines */
@@ -204,6 +203,33 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
{"FM Radio-INPUT1_MONO", 0x0278, 0x9002}
};
+
+struct xc5000_fw_cfg {
+ char *name;
+ u16 size;
+};
+
+static const struct xc5000_fw_cfg xc5000a_1_6_114 = {
+ .name = "dvb-fe-xc5000-1.6.114.fw",
+ .size = 12401,
+};
+
+static const struct xc5000_fw_cfg xc5000c_41_024_5_31875 = {
+ .name = "dvb-fe-xc5000c-41.024.5-31875.fw",
+ .size = 16503,
+};
+
+static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id)
+{
+ switch (chip_id) {
+ default:
+ case XC5000A:
+ return &xc5000a_1_6_114;
+ case XC5000C:
+ return &xc5000c_41_024_5_31875;
+ }
+}
+
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);
@@ -552,12 +578,14 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
struct xc5000_priv *priv = fe->tuner_priv;
const struct firmware *fw;
int ret;
+ const struct xc5000_fw_cfg *desired_fw =
+ xc5000_assign_firmware(priv->chip_id);
/* request the firmware, this will block and timeout */
printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
- XC5000_DEFAULT_FIRMWARE);
+ desired_fw->name);
- ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
+ ret = request_firmware(&fw, desired_fw->name,
priv->i2c_props.adap->dev.parent);
if (ret) {
printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
@@ -569,7 +597,7 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
ret = XC_RESULT_SUCCESS;
}
- if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) {
+ if (fw->size != desired_fw->size) {
printk(KERN_ERR "xc5000: firmware incorrect size\n");
ret = XC_RESULT_RESET_FAILURE;
} else {
@@ -628,20 +656,13 @@ static void xc_debug_dump(struct xc5000_priv *priv)
dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
}
-/*
- * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
- * So, the amount of the needed bandwith is given by:
- * Bw = Symbol_rate * (1 + 0.15)
- * As such, the maximum symbol rate supported by 6 MHz is given by:
- * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
- */
-#define MAX_SYMBOL_RATE_6MHz 5217391
-
-static int xc5000_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int xc5000_set_params(struct dvb_frontend *fe)
{
+ int ret, b;
struct xc5000_priv *priv = fe->tuner_priv;
- int ret;
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ u32 freq = fe->dtv_property_cache.frequency;
+ u32 delsys = fe->dtv_property_cache.delivery_system;
if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
@@ -650,88 +671,69 @@ static int xc5000_set_params(struct dvb_frontend *fe,
}
}
- dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
-
- 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() frequency=%d (Hz)\n", __func__, freq);
+
+ switch (delsys) {
+ case SYS_ATSC:
+ dprintk(1, "%s() VSB modulation\n", __func__);
+ priv->rf_mode = XC_RF_MODE_AIR;
+ priv->freq_hz = freq - 1750000;
+ priv->video_standard = DTV6;
+ break;
+ case SYS_DVBC_ANNEX_B:
+ dprintk(1, "%s() QAM modulation\n", __func__);
+ priv->rf_mode = XC_RF_MODE_CABLE;
+ priv->freq_hz = freq - 1750000;
+ priv->video_standard = DTV6;
+ break;
+ case SYS_DVBT:
+ case SYS_DVBT2:
dprintk(1, "%s() OFDM\n", __func__);
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
- priv->bandwidth = BANDWIDTH_6_MHZ;
+ switch (bw) {
+ case 6000000:
priv->video_standard = DTV6;
- priv->freq_hz = params->frequency - 1750000;
+ priv->freq_hz = freq - 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;
+ case 7000000:
+ priv->video_standard = DTV7;
+ priv->freq_hz = freq - 2250000;
+ break;
+ case 8000000:
priv->video_standard = DTV8;
- priv->freq_hz = params->frequency - 2750000;
+ priv->freq_hz = freq - 2750000;
break;
default:
printk(KERN_ERR "xc5000 bandwidth not set!\n");
return -EINVAL;
}
priv->rf_mode = XC_RF_MODE_AIR;
- } else if (fe->ops.info.type == FE_QAM) {
- switch (params->u.qam.modulation) {
- case QAM_256:
- case QAM_AUTO:
- case QAM_16:
- case QAM_32:
- case QAM_64:
- case QAM_128:
- dprintk(1, "%s() QAM modulation\n", __func__);
- priv->rf_mode = XC_RF_MODE_CABLE;
- /*
- * Using a 8MHz bandwidth sometimes fail
- * with 6MHz-spaced channels, due to inter-carrier
- * interference. So, use DTV6 firmware
- */
- if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) {
- priv->bandwidth = BANDWIDTH_6_MHZ;
- priv->video_standard = DTV6;
- priv->freq_hz = params->frequency - 1750000;
- } else {
- priv->bandwidth = BANDWIDTH_8_MHZ;
- priv->video_standard = DTV7_8;
- priv->freq_hz = params->frequency - 2750000;
- }
- break;
- default:
- dprintk(1, "%s() Unsupported QAM type\n", __func__);
- return -EINVAL;
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
+ dprintk(1, "%s() QAM modulation\n", __func__);
+ priv->rf_mode = XC_RF_MODE_CABLE;
+ if (bw <= 6000000) {
+ priv->video_standard = DTV6;
+ priv->freq_hz = freq - 1750000;
+ b = 6;
+ } else if (bw <= 7000000) {
+ priv->video_standard = DTV7;
+ priv->freq_hz = freq - 2250000;
+ b = 7;
+ } else {
+ priv->video_standard = DTV7_8;
+ priv->freq_hz = freq - 2750000;
+ b = 8;
}
- } else {
- printk(KERN_ERR "xc5000 modulation type not supported!\n");
+ dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__,
+ b, bw);
+ break;
+ default:
+ printk(KERN_ERR "xc5000: delivery system is not supported!\n");
return -EINVAL;
}
- dprintk(1, "%s() frequency=%d (compensated)\n",
- __func__, priv->freq_hz);
+ dprintk(1, "%s() frequency=%d (compensated to %d)\n",
+ __func__, freq, priv->freq_hz);
ret = xc_SetSignalSource(priv, priv->rf_mode);
if (ret != XC_RESULT_SUCCESS) {
@@ -763,6 +765,8 @@ static int xc5000_set_params(struct dvb_frontend *fe,
if (debug)
xc_debug_dump(priv);
+ priv->bandwidth = bw;
+
return 0;
}
@@ -968,6 +972,14 @@ static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
return 0;
}
+static int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ dprintk(1, "%s()\n", __func__);
+ *freq = priv->if_khz * 1000;
+ return 0;
+}
+
static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
{
struct xc5000_priv *priv = fe->tuner_priv;
@@ -1108,6 +1120,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
.set_params = xc5000_set_params,
.set_analog_params = xc5000_set_analog_params,
.get_frequency = xc5000_get_frequency,
+ .get_if_frequency = xc5000_get_if_frequency,
.get_bandwidth = xc5000_get_bandwidth,
.get_status = xc5000_get_status
};
@@ -1135,7 +1148,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
break;
case 1:
/* new tuner instance */
- priv->bandwidth = BANDWIDTH_6_MHZ;
+ priv->bandwidth = 6000000;
fe->tuner_priv = priv;
break;
default:
@@ -1154,6 +1167,13 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
if (priv->radio_input == 0)
priv->radio_input = cfg->radio_input;
+ /* don't override chip id if it's already been set
+ unless explicitly specified */
+ if ((priv->chip_id == 0) || (cfg->chip_id))
+ /* use default chip id if none specified, set to 0 so
+ it can be overridden if this is a hybrid driver */
+ priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0;
+
/* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware.
*/
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index e2957451b532..3396f8e02b40 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -27,10 +27,15 @@
struct dvb_frontend;
struct i2c_adapter;
+#define XC5000A 1
+#define XC5000C 2
+
struct xc5000_config {
u8 i2c_address;
u32 if_khz;
u8 radio_input;
+
+ int chip_id;
};
/* xc5000 callback command */
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 2df1b0214dcd..b1e8c99f469b 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -86,7 +86,8 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
fc->demux.stop_feed = flexcop_dvb_stop_feed;
fc->demux.write_to_decoder = NULL;
- if ((ret = dvb_dmx_init(&fc->demux)) < 0) {
+ ret = dvb_dmx_init(&fc->demux);
+ if (ret < 0) {
err("dvb_dmx failed: error %d", ret);
goto err_dmx;
}
@@ -96,32 +97,42 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
fc->dmxdev.filternum = fc->demux.feednum;
fc->dmxdev.demux = &fc->demux.dmx;
fc->dmxdev.capabilities = 0;
- if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) {
+ ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter);
+ if (ret < 0) {
err("dvb_dmxdev_init failed: error %d", ret);
goto err_dmx_dev;
}
- if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
+ ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend);
+ if (ret < 0) {
err("adding hw_frontend to dmx failed: error %d", ret);
goto err_dmx_add_hw_frontend;
}
fc->mem_frontend.source = DMX_MEMORY_FE;
- if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) {
+ ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend);
+ if (ret < 0) {
err("adding mem_frontend to dmx failed: error %d", ret);
goto err_dmx_add_mem_frontend;
}
- if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
+ ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend);
+ if (ret < 0) {
err("connect frontend failed: error %d", ret);
goto err_connect_frontend;
}
- dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
+ ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
+ if (ret < 0) {
+ err("dvb_net_init failed: error %d", ret);
+ goto err_net;
+ }
fc->init_state |= FC_STATE_DVB_INIT;
return 0;
+err_net:
+ fc->demux.dmx.disconnect_frontend(&fc->demux.dmx);
err_connect_frontend:
fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend);
err_dmx_add_mem_frontend:
@@ -254,7 +265,8 @@ int flexcop_device_initialize(struct flexcop_device *fc)
flexcop_hw_filter_init(fc);
flexcop_smc_ctrl(fc, 0);
- if ((ret = flexcop_dvb_init(fc)))
+ ret = flexcop_dvb_init(fc);
+ if (ret)
goto error;
/* i2c has to be done before doing EEProm stuff -
@@ -272,7 +284,8 @@ int flexcop_device_initialize(struct flexcop_device *fc)
} else
warn("reading of MAC address failed.\n");
- if ((ret = flexcop_frontend_init(fc)))
+ ret = flexcop_frontend_init(fc);
+ if (ret)
goto error;
flexcop_device_name(fc,"initialization of","complete");
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index caa4e18ed1c1..430b3eb11815 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -386,7 +386,7 @@ static int dst_set_freq(struct dst_state *state, u32 freq)
return 0;
}
-static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth)
+static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth)
{
state->bandwidth = bandwidth;
@@ -394,7 +394,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth)
return -EOPNOTSUPP;
switch (bandwidth) {
- case BANDWIDTH_6_MHZ:
+ case 6000000:
if (state->dst_hw_cap & DST_TYPE_HAS_CA)
state->tx_tuna[7] = 0x06;
else {
@@ -402,7 +402,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth)
state->tx_tuna[7] = 0x00;
}
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
if (state->dst_hw_cap & DST_TYPE_HAS_CA)
state->tx_tuna[7] = 0x07;
else {
@@ -410,7 +410,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth)
state->tx_tuna[7] = 0x00;
}
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
if (state->dst_hw_cap & DST_TYPE_HAS_CA)
state->tx_tuna[7] = 0x08;
else {
@@ -1561,7 +1561,7 @@ static int dst_init(struct dvb_frontend *fe)
state->tone = SEC_TONE_OFF;
state->diseq_flags = 0;
state->k22 = 0x02;
- state->bandwidth = BANDWIDTH_7_MHZ;
+ state->bandwidth = 7000000;
state->cur_jiff = jiffies;
if (state->dst_type == DST_TYPE_IS_SAT)
memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
@@ -1609,8 +1609,9 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
return retval;
}
-static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dst_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
int retval = -EINVAL;
struct dst_state *state = fe->demodulator_priv;
@@ -1623,17 +1624,17 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
if (state->dst_type == DST_TYPE_IS_SAT) {
if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
dst_set_inversion(state, p->inversion);
- dst_set_fec(state, p->u.qpsk.fec_inner);
- dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+ dst_set_fec(state, p->fec_inner);
+ dst_set_symbolrate(state, p->symbol_rate);
dst_set_polarization(state);
- dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+ dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate);
} else if (state->dst_type == DST_TYPE_IS_TERR)
- dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+ dst_set_bandwidth(state, p->bandwidth_hz);
else if (state->dst_type == DST_TYPE_IS_CABLE) {
- dst_set_fec(state, p->u.qam.fec_inner);
- dst_set_symbolrate(state, p->u.qam.symbol_rate);
- dst_set_modulation(state, p->u.qam.modulation);
+ dst_set_fec(state, p->fec_inner);
+ dst_set_symbolrate(state, p->symbol_rate);
+ dst_set_modulation(state, p->modulation);
}
retval = dst_write_tuna(fe);
}
@@ -1642,31 +1643,32 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
}
static int dst_tune_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* p,
+ bool re_tune,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status)
{
struct dst_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- if (p != NULL) {
+ if (re_tune) {
dst_set_freq(state, p->frequency);
dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
if (state->dst_type == DST_TYPE_IS_SAT) {
if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
dst_set_inversion(state, p->inversion);
- dst_set_fec(state, p->u.qpsk.fec_inner);
- dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+ dst_set_fec(state, p->fec_inner);
+ dst_set_symbolrate(state, p->symbol_rate);
dst_set_polarization(state);
- dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+ dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate);
} else if (state->dst_type == DST_TYPE_IS_TERR)
- dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+ dst_set_bandwidth(state, p->bandwidth_hz);
else if (state->dst_type == DST_TYPE_IS_CABLE) {
- dst_set_fec(state, p->u.qam.fec_inner);
- dst_set_symbolrate(state, p->u.qam.symbol_rate);
- dst_set_modulation(state, p->u.qam.modulation);
+ dst_set_fec(state, p->fec_inner);
+ dst_set_symbolrate(state, p->symbol_rate);
+ dst_set_modulation(state, p->modulation);
}
dst_write_tuna(fe);
}
@@ -1683,22 +1685,23 @@ static int dst_get_tuning_algo(struct dvb_frontend *fe)
return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW;
}
-static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dst_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dst_state *state = fe->demodulator_priv;
p->frequency = state->decode_freq;
if (state->dst_type == DST_TYPE_IS_SAT) {
if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
p->inversion = state->inversion;
- p->u.qpsk.symbol_rate = state->symbol_rate;
- p->u.qpsk.fec_inner = dst_get_fec(state);
+ p->symbol_rate = state->symbol_rate;
+ p->fec_inner = dst_get_fec(state);
} else if (state->dst_type == DST_TYPE_IS_TERR) {
- p->u.ofdm.bandwidth = state->bandwidth;
+ p->bandwidth_hz = state->bandwidth;
} else if (state->dst_type == DST_TYPE_IS_CABLE) {
- p->u.qam.symbol_rate = state->symbol_rate;
- p->u.qam.fec_inner = dst_get_fec(state);
- p->u.qam.modulation = dst_get_modulation(state);
+ p->symbol_rate = state->symbol_rate;
+ p->fec_inner = dst_get_fec(state);
+ p->modulation = dst_get_modulation(state);
}
return 0;
@@ -1756,10 +1759,9 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad
EXPORT_SYMBOL(dst_attach);
static struct dvb_frontend_ops dst_dvbt_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "DST DVB-T",
- .type = FE_OFDM,
.frequency_min = 137000000,
.frequency_max = 858000000,
.frequency_stepsize = 166667,
@@ -1786,10 +1788,9 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
};
static struct dvb_frontend_ops dst_dvbs_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "DST DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1000, /* kHz for QPSK frontends */
@@ -1816,10 +1817,9 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
};
static struct dvb_frontend_ops dst_dvbc_ops = {
-
+ .delsys = { SYS_DVBC_ANNEX_A },
.info = {
.name = "DST DVB-C",
- .type = FE_QAM,
.frequency_stepsize = 62500,
.frequency_min = 51000000,
.frequency_max = 858000000,
@@ -1846,9 +1846,9 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
};
static struct dvb_frontend_ops dst_atsc_ops = {
+ .delsys = { SYS_ATSC },
.info = {
.name = "DST ATSC",
- .type = FE_ATSC,
.frequency_stepsize = 62500,
.frequency_min = 510000000,
.frequency_max = 858000000,
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index d88cf2add82b..d70d98f1a571 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -124,7 +124,7 @@ struct dst_state {
u16 decode_snr;
unsigned long cur_jiff;
u8 k22;
- fe_bandwidth_t bandwidth;
+ u32 bandwidth;
u32 dst_hw_cap;
u8 dst_fw_version;
fe_sec_mini_cmd_t minicmd;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 521d69104982..81fab9adc1ca 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -19,6 +19,8 @@
*
*/
+#define pr_fmt(fmt) "dvb_bt8xx: " fmt
+
#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -148,8 +150,9 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
+static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u32 div;
unsigned char bs = 0;
unsigned char cp = 0;
@@ -157,18 +160,18 @@ static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_f
if (buf_len < 5)
return -EINVAL;
- div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+ div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
- if (params->frequency < 542000000)
+ if (c->frequency < 542000000)
cp = 0xb4;
- else if (params->frequency < 771000000)
+ else if (c->frequency < 771000000)
cp = 0xbc;
else
cp = 0xf4;
- if (params->frequency == 0)
+ if (c->frequency == 0)
bs = 0x03;
- else if (params->frequency < 443250000)
+ else if (c->frequency < 443250000)
bs = 0x02;
else
bs = 0x08;
@@ -191,13 +194,12 @@ static struct zl10353_config thomson_dtt7579_zl10353_config = {
.demod_address = 0x0f,
};
-static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int cx24108_tuner_set_params(struct dvb_frontend *fe)
{
- u32 freq = params->frequency;
-
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 freq = c->frequency;
int i, a, n, pump;
u32 band, pll;
-
u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
1576000,1718000,1856000,2036000,2150000};
u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
@@ -205,7 +207,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
0x00120000,0x00140000};
#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
- printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq);
+ dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq);
/* This is really the bit driving the tuner chip cx24108 */
@@ -216,7 +218,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
/* decide which VCO to use for the input frequency */
for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++);
- printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
+ dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq);
band=bandsel[i];
/* the gain values must be set by SetSymbolrate */
/* compute the pll divider needed, from Conexant data sheet,
@@ -232,7 +234,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
((a&0x1f)<<11);
/* everything is shifted left 11 bits to left-align the bits in the
32bit word. Output to the tuner goes MSB-aligned, after all */
- printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a);
+ dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a);
cx24110_pll_write(fe,band);
/* set vga and vca to their widest-band settings, as a precaution.
SetSymbolrate might not be called to set this up */
@@ -267,31 +269,32 @@ static struct cx24110_config pctvsat_config = {
.demod_address = 0x55,
};
-static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
u8 cfg, cpump, band_select;
u8 data[4];
u32 div;
struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
- div = (36000000 + params->frequency + 83333) / 166666;
+ div = (36000000 + c->frequency + 83333) / 166666;
cfg = 0x88;
- if (params->frequency < 175000000)
+ if (c->frequency < 175000000)
cpump = 2;
- else if (params->frequency < 390000000)
+ else if (c->frequency < 390000000)
cpump = 1;
- else if (params->frequency < 470000000)
+ else if (c->frequency < 470000000)
cpump = 2;
- else if (params->frequency < 750000000)
+ else if (c->frequency < 750000000)
cpump = 2;
else
cpump = 3;
- if (params->frequency < 175000000)
+ if (c->frequency < 175000000)
band_select = 0x0e;
- else if (params->frequency < 470000000)
+ else if (c->frequency < 470000000)
band_select = 0x05;
else
band_select = 0x03;
@@ -342,50 +345,51 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
+static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u32 div;
unsigned char bs = 0;
unsigned char cp = 0;
if (buf_len < 5) return -EINVAL;
- div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+ div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
- if (params->frequency < 150000000)
+ if (c->frequency < 150000000)
cp = 0xB4;
- else if (params->frequency < 173000000)
+ else if (c->frequency < 173000000)
cp = 0xBC;
- else if (params->frequency < 250000000)
+ else if (c->frequency < 250000000)
cp = 0xB4;
- else if (params->frequency < 400000000)
+ else if (c->frequency < 400000000)
cp = 0xBC;
- else if (params->frequency < 420000000)
+ else if (c->frequency < 420000000)
cp = 0xF4;
- else if (params->frequency < 470000000)
+ else if (c->frequency < 470000000)
cp = 0xFC;
- else if (params->frequency < 600000000)
+ else if (c->frequency < 600000000)
cp = 0xBC;
- else if (params->frequency < 730000000)
+ else if (c->frequency < 730000000)
cp = 0xF4;
else
cp = 0xFC;
- if (params->frequency < 150000000)
+ if (c->frequency < 150000000)
bs = 0x01;
- else if (params->frequency < 173000000)
+ else if (c->frequency < 173000000)
bs = 0x01;
- else if (params->frequency < 250000000)
+ else if (c->frequency < 250000000)
bs = 0x02;
- else if (params->frequency < 400000000)
+ else if (c->frequency < 400000000)
bs = 0x02;
- else if (params->frequency < 420000000)
+ else if (c->frequency < 420000000)
bs = 0x02;
- else if (params->frequency < 470000000)
+ else if (c->frequency < 470000000)
bs = 0x02;
- else if (params->frequency < 600000000)
+ else if (c->frequency < 600000000)
bs = 0x08;
- else if (params->frequency < 730000000)
+ else if (c->frequency < 730000000)
bs = 0x08;
else
bs = 0x08;
@@ -461,25 +465,26 @@ static struct or51211_config or51211_config = {
.sleep = or51211_sleep,
};
-static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
u8 buf[4];
u32 div;
struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
- div = (params->frequency + 36166667) / 166667;
+ div = (c->frequency + 36166667) / 166667;
buf[0] = (div >> 8) & 0x7F;
buf[1] = div & 0xFF;
buf[2] = 0x85;
- if ((params->frequency >= 47000000) && (params->frequency < 153000000))
+ if ((c->frequency >= 47000000) && (c->frequency < 153000000))
buf[3] = 0x01;
- else if ((params->frequency >= 153000000) && (params->frequency < 430000000))
+ else if ((c->frequency >= 153000000) && (c->frequency < 430000000))
buf[3] = 0x02;
- else if ((params->frequency >= 430000000) && (params->frequency < 824000000))
+ else if ((c->frequency >= 430000000) && (c->frequency < 824000000))
buf[3] = 0x0C;
- else if ((params->frequency >= 824000000) && (params->frequency < 863000000))
+ else if ((c->frequency >= 824000000) && (c->frequency < 863000000))
buf[3] = 0x8C;
else
return -EINVAL;
@@ -513,31 +518,31 @@ static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
+static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len)
{
u32 div;
- struct dvb_ofdm_parameters *op = &params->u.ofdm;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
if (buf_len < 5)
return -EINVAL;
- div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+ div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
pllbuf[0] = 0x61;
pllbuf[1] = (div >> 8) & 0x7F;
pllbuf[2] = div & 0xFF;
pllbuf[3] = 0x85;
- dprintk("frequency %u, div %u\n", params->frequency, div);
+ dprintk("frequency %u, div %u\n", c->frequency, div);
- if (params->frequency < 470000000)
+ if (c->frequency < 470000000)
pllbuf[4] = 0x02;
- else if (params->frequency > 823000000)
+ else if (c->frequency > 823000000)
pllbuf[4] = 0x88;
else
pllbuf[4] = 0x08;
- if (op->bandwidth == 8)
+ if (c->bandwidth_hz == 8000000)
pllbuf[4] |= 0x04;
return 5;
@@ -663,7 +668,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
/* DST is not a frontend driver !!! */
state = kmalloc(sizeof (struct dst_state), GFP_KERNEL);
if (!state) {
- printk("dvb_bt8xx: No memory\n");
+ pr_err("No memory\n");
break;
}
/* Setup the Card */
@@ -673,7 +678,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
state->dst_ca = NULL;
/* DST is not a frontend, attaching the ASIC */
if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
- printk("%s: Could not find a Twinhan DST.\n", __func__);
+ pr_err("%s: Could not find a Twinhan DST\n", __func__);
break;
}
/* Attach other DST peripherals if any */
@@ -702,14 +707,14 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
}
if (card->fe == NULL)
- printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
+ pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
card->bt->dev->vendor,
card->bt->dev->device,
card->bt->dev->subsystem_vendor,
card->bt->dev->subsystem_device);
else
if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
- printk("dvb-bt8xx: Frontend registration failed!\n");
+ pr_err("Frontend registration failed!\n");
dvb_frontend_detach(card->fe);
card->fe = NULL;
}
@@ -723,7 +728,7 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
THIS_MODULE, &card->bt->dev->dev,
adapter_nr);
if (result < 0) {
- printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
+ pr_err("dvb_register_adapter failed (errno = %d)\n", result);
return result;
}
card->dvb_adapter.priv = card;
@@ -741,66 +746,69 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
card->demux.stop_feed = dvb_bt8xx_stop_feed;
card->demux.write_to_decoder = NULL;
- if ((result = dvb_dmx_init(&card->demux)) < 0) {
- printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
-
- dvb_unregister_adapter(&card->dvb_adapter);
- return result;
+ result = dvb_dmx_init(&card->demux);
+ if (result < 0) {
+ pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+ goto err_unregister_adaptor;
}
card->dmxdev.filternum = 256;
card->dmxdev.demux = &card->demux.dmx;
card->dmxdev.capabilities = 0;
- if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) {
- printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result);
-
- dvb_dmx_release(&card->demux);
- dvb_unregister_adapter(&card->dvb_adapter);
- return result;
+ result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter);
+ if (result < 0) {
+ pr_err("dvb_dmxdev_init failed (errno = %d)\n", result);
+ goto err_dmx_release;
}
card->fe_hw.source = DMX_FRONTEND_0;
- if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw)) < 0) {
- printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
-
- dvb_dmxdev_release(&card->dmxdev);
- dvb_dmx_release(&card->demux);
- dvb_unregister_adapter(&card->dvb_adapter);
- return result;
+ result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw);
+ if (result < 0) {
+ pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+ goto err_dmxdev_release;
}
card->fe_mem.source = DMX_MEMORY_FE;
- if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem)) < 0) {
- printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
-
- card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
- dvb_dmxdev_release(&card->dmxdev);
- dvb_dmx_release(&card->demux);
- dvb_unregister_adapter(&card->dvb_adapter);
- return result;
+ result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem);
+ if (result < 0) {
+ pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+ goto err_remove_hw_frontend;
}
- if ((result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw)) < 0) {
- printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
-
- card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
- card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
- dvb_dmxdev_release(&card->dmxdev);
- dvb_dmx_release(&card->demux);
- dvb_unregister_adapter(&card->dvb_adapter);
- return result;
+ result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw);
+ if (result < 0) {
+ pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+ goto err_remove_mem_frontend;
}
- dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
+ result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
+ if (result < 0) {
+ pr_err("dvb_net_init failed (errno = %d)\n", result);
+ goto err_disconnect_frontend;
+ }
tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
frontend_init(card, type);
return 0;
+
+err_disconnect_frontend:
+ card->demux.dmx.disconnect_frontend(&card->demux.dmx);
+err_remove_mem_frontend:
+ card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
+err_remove_hw_frontend:
+ card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
+err_dmxdev_release:
+ dvb_dmxdev_release(&card->dmxdev);
+err_dmx_release:
+ dvb_dmx_release(&card->demux);
+err_unregister_adaptor:
+ dvb_unregister_adapter(&card->dvb_adapter);
+ return result;
}
static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
@@ -881,8 +889,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
break;
default:
- printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n",
- sub->core->type);
+ pr_err("Unknown bttv card type: %d\n", sub->core->type);
kfree(card);
return -ENODEV;
}
@@ -890,16 +897,14 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name);
if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
- printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr);
+ pr_err("no pci device for card %d\n", card->bttv_nr);
kfree(card);
return -ENODEV;
}
if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
- printk("dvb_bt8xx: unable to determine DMA core of card %d,\n",
- card->bttv_nr);
- printk("dvb_bt8xx: if you have the ALSA bt87x audio driver "
- "installed, try removing it.\n");
+ pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr);
+ pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n");
kfree(card);
return -ENODEV;
diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c
index d1e91bc80e78..d88c4aa7d24d 100644
--- a/drivers/media/dvb/ddbridge/ddbridge-core.c
+++ b/drivers/media/dvb/ddbridge/ddbridge-core.c
@@ -578,9 +578,10 @@ static int demod_attach_drxk(struct ddb_input *input)
struct drxk_config config;
memset(&config, 0, sizeof(config));
+ config.microcode_name = "drxk_a3.mc";
config.adr = 0x29 + (input->nr & 1);
- fe = input->fe = dvb_attach(drxk_attach, &config, i2c, &input->fe2);
+ fe = input->fe = dvb_attach(drxk_attach, &config, i2c);
if (!input->fe) {
printk(KERN_ERR "No DRXK found!\n");
return -ENODEV;
diff --git a/drivers/media/dvb/ddbridge/ddbridge.h b/drivers/media/dvb/ddbridge/ddbridge.h
index 6d14893218f4..8b1b41d2a52d 100644
--- a/drivers/media/dvb/ddbridge/ddbridge.h
+++ b/drivers/media/dvb/ddbridge/ddbridge.h
@@ -32,8 +32,6 @@
#include <asm/dma.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/ca.h>
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
#include <linux/socket.h>
#include "dmxdev.h"
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index 55e6533f15e9..a609b3a9b146 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -1115,11 +1115,14 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
if (ret < 0)
goto err_remove_mem_frontend;
- ret = frontend_init(dev);
+ ret = dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
if (ret < 0)
goto err_disconnect_frontend;
- dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
+ ret = frontend_init(dev);
+ if (ret < 0)
+ goto err_dvb_net;
+
dm1105_ir_init(dev);
INIT_WORK(&dev->work, dm1105_dmx_buffer);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index e4b5c03ae516..73970cd97af1 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -29,7 +29,6 @@
#include <linux/ioctl.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include "dmxdev.h"
static int debug;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 7ea517b7e186..9be65a3b931f 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1306,6 +1306,10 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
/* fragment the packets & store in the buffer */
while (fragpos < count) {
fraglen = ca->slot_info[slot].link_buf_size - 2;
+ if (fraglen < 0)
+ break;
+ if (fraglen > HOST_LINK_BUF_SIZE - 2)
+ fraglen = HOST_LINK_BUF_SIZE - 2;
if ((count - fragpos) < fraglen)
fraglen = count - fragpos;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 2c0acdb4d811..39696c6a4ed7 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -25,6 +25,9 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/
+/* Enables DVBv3 compatibility bits at the headers */
+#define __DVB_CORE__
+
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -105,7 +108,6 @@ struct dvb_frontend_private {
/* thread/frontend values */
struct dvb_device *dvbdev;
- struct dvb_frontend_parameters parameters_in;
struct dvb_frontend_parameters parameters_out;
struct dvb_fe_events events;
struct semaphore sem;
@@ -139,6 +141,64 @@ struct dvb_frontend_private {
};
static void dvb_frontend_wakeup(struct dvb_frontend *fe);
+static int dtv_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p_out);
+static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p);
+
+static bool has_get_frontend(struct dvb_frontend *fe)
+{
+ return fe->ops.get_frontend != NULL;
+}
+
+/*
+ * Due to DVBv3 API calls, a delivery system should be mapped into one of
+ * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC),
+ * otherwise, a DVBv3 call will fail.
+ */
+enum dvbv3_emulation_type {
+ DVBV3_UNKNOWN,
+ DVBV3_QPSK,
+ DVBV3_QAM,
+ DVBV3_OFDM,
+ DVBV3_ATSC,
+};
+
+static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
+{
+ switch (delivery_system) {
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
+ return DVBV3_QAM;
+ case SYS_DVBS:
+ case SYS_DVBS2:
+ case SYS_TURBO:
+ case SYS_ISDBS:
+ case SYS_DSS:
+ return DVBV3_QPSK;
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ case SYS_ISDBT:
+ case SYS_DMBTH:
+ return DVBV3_OFDM;
+ case SYS_ATSC:
+ case SYS_DVBC_ANNEX_B:
+ return DVBV3_ATSC;
+ case SYS_UNDEFINED:
+ case SYS_ISDBC:
+ case SYS_DVBH:
+ case SYS_DAB:
+ case SYS_ATSCMH:
+ default:
+ /*
+ * Doesn't know how to emulate those types and/or
+ * there's no frontend driver from this type yet
+ * with some emulation code, so, we're not sure yet how
+ * to handle them, or they're not compatible with a DVBv3 call.
+ */
+ return DVBV3_UNKNOWN;
+ }
+}
static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
{
@@ -149,8 +209,8 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
dprintk ("%s\n", __func__);
- if ((status & FE_HAS_LOCK) && fe->ops.get_frontend)
- fe->ops.get_frontend(fe, &fepriv->parameters_out);
+ if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
+ dtv_get_frontend(fe, &fepriv->parameters_out);
mutex_lock(&events->mtx);
@@ -277,12 +337,13 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
int ready = 0;
int fe_set_err = 0;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
- int original_inversion = fepriv->parameters_in.inversion;
- u32 original_frequency = fepriv->parameters_in.frequency;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
+ int original_inversion = c->inversion;
+ u32 original_frequency = c->frequency;
/* are we using autoinversion? */
autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
- (fepriv->parameters_in.inversion == INVERSION_AUTO));
+ (c->inversion == INVERSION_AUTO));
/* setup parameters correctly */
while(!ready) {
@@ -348,19 +409,20 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
/* set the frontend itself */
- fepriv->parameters_in.frequency += fepriv->lnb_drift;
+ c->frequency += fepriv->lnb_drift;
if (autoinversion)
- fepriv->parameters_in.inversion = fepriv->inversion;
+ c->inversion = fepriv->inversion;
+ tmp = *c;
if (fe->ops.set_frontend)
- fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in);
- fepriv->parameters_out = fepriv->parameters_in;
+ fe_set_err = fe->ops.set_frontend(fe);
+ *c = tmp;
if (fe_set_err < 0) {
fepriv->state = FESTATE_ERROR;
return fe_set_err;
}
- fepriv->parameters_in.frequency = original_frequency;
- fepriv->parameters_in.inversion = original_inversion;
+ c->frequency = original_frequency;
+ c->inversion = original_inversion;
fepriv->auto_sub_step++;
return 0;
@@ -371,6 +433,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
fe_status_t s = 0;
int retval = 0;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
/* if we've got no parameters, just keep idling */
if (fepriv->state & FESTATE_IDLE) {
@@ -382,10 +445,10 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
/* in SCAN mode, we just set the frontend when asked and leave it alone */
if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
if (fepriv->state & FESTATE_RETUNE) {
+ tmp = *c;
if (fe->ops.set_frontend)
- retval = fe->ops.set_frontend(fe,
- &fepriv->parameters_in);
- fepriv->parameters_out = fepriv->parameters_in;
+ retval = fe->ops.set_frontend(fe);
+ *c = tmp;
if (retval < 0)
fepriv->state = FESTATE_ERROR;
else
@@ -415,8 +478,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
/* if we're tuned, then we have determined the correct inversion */
if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
- (fepriv->parameters_in.inversion == INVERSION_AUTO)) {
- fepriv->parameters_in.inversion = fepriv->inversion;
+ (c->inversion == INVERSION_AUTO)) {
+ c->inversion = fepriv->inversion;
}
return;
}
@@ -507,7 +570,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
return 1;
if (fepriv->dvbdev->writers == 1)
- if (time_after(jiffies, fepriv->release_jiffies +
+ if (time_after_eq(jiffies, fepriv->release_jiffies +
dvb_shutdown_timeout * HZ))
return 1;
@@ -540,7 +603,7 @@ static int dvb_frontend_thread(void *data)
fe_status_t s;
enum dvbfe_algo algo;
- struct dvb_frontend_parameters *params;
+ bool re_tune = false;
dprintk("%s\n", __func__);
@@ -589,18 +652,17 @@ restart:
switch (algo) {
case DVBFE_ALGO_HW:
dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
- params = NULL; /* have we been asked to RETUNE ? */
if (fepriv->state & FESTATE_RETUNE) {
dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
- params = &fepriv->parameters_in;
+ re_tune = true;
fepriv->state = FESTATE_TUNED;
+ } else {
+ re_tune = false;
}
if (fe->ops.tune)
- fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
- if (params)
- fepriv->parameters_out = *params;
+ fe->ops.tune(fe, re_tune, fepriv->tune_mode_flags, &fepriv->delay, &s);
if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
dprintk("%s: state changed, adding current state\n", __func__);
@@ -624,7 +686,7 @@ restart:
*/
if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
if (fe->ops.search) {
- fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in);
+ fepriv->algo_status = fe->ops.search(fe);
/* We did do a search as was requested, the flags are
* now unset as well and has the flags wrt to search.
*/
@@ -633,14 +695,11 @@ restart:
}
}
/* Track the carrier if the search was successful */
- if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
- if (fe->ops.track)
- fe->ops.track(fe, &fepriv->parameters_in);
- } else {
+ if (fepriv->algo_status != DVBFE_ALGO_SEARCH_SUCCESS) {
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
fepriv->delay = HZ / 2;
}
- fepriv->parameters_out = fepriv->parameters_in;
+ dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
fe->ops.read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s); /* update event list */
@@ -807,52 +866,40 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
fe->dvb->num,fe->id);
}
-static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *parms)
+static int dvb_frontend_check_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u32 freq_min;
u32 freq_max;
/* range check: frequency */
dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);
- if ((freq_min && parms->frequency < freq_min) ||
- (freq_max && parms->frequency > freq_max)) {
+ if ((freq_min && c->frequency < freq_min) ||
+ (freq_max && c->frequency > freq_max)) {
printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
- fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max);
+ fe->dvb->num, fe->id, c->frequency, freq_min, freq_max);
return -EINVAL;
}
/* range check: symbol rate */
- if (fe->ops.info.type == FE_QPSK) {
+ switch (c->delivery_system) {
+ case SYS_DVBS:
+ case SYS_DVBS2:
+ case SYS_TURBO:
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
if ((fe->ops.info.symbol_rate_min &&
- parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
+ c->symbol_rate < fe->ops.info.symbol_rate_min) ||
(fe->ops.info.symbol_rate_max &&
- parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
+ c->symbol_rate > fe->ops.info.symbol_rate_max)) {
printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
- fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate,
- fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+ fe->dvb->num, fe->id, c->symbol_rate,
+ fe->ops.info.symbol_rate_min,
+ fe->ops.info.symbol_rate_max);
return -EINVAL;
}
-
- } else if (fe->ops.info.type == FE_QAM) {
- if ((fe->ops.info.symbol_rate_min &&
- parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
- (fe->ops.info.symbol_rate_max &&
- parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
- printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
- fe->dvb->num, fe->id, parms->u.qam.symbol_rate,
- fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
- return -EINVAL;
- }
- }
-
- /* check for supported modulation */
- if (fe->ops.info.type == FE_QAM &&
- (parms->u.qam.modulation > QAM_AUTO ||
- !((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) {
- printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n",
- fe->dvb->num, fe->id, parms->u.qam.modulation);
- return -EINVAL;
+ default:
+ break;
}
return 0;
@@ -862,32 +909,59 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int i;
+ u32 delsys;
+ delsys = c->delivery_system;
memset(c, 0, sizeof(struct dtv_frontend_properties));
+ c->delivery_system = delsys;
c->state = DTV_CLEAR;
- c->delivery_system = SYS_UNDEFINED;
- c->inversion = INVERSION_AUTO;
- c->fec_inner = FEC_AUTO;
+
+ dprintk("%s() Clearing cache for delivery system %d\n", __func__,
+ c->delivery_system);
+
c->transmission_mode = TRANSMISSION_MODE_AUTO;
- c->bandwidth_hz = BANDWIDTH_AUTO;
+ c->bandwidth_hz = 0; /* AUTO */
c->guard_interval = GUARD_INTERVAL_AUTO;
c->hierarchy = HIERARCHY_AUTO;
- c->symbol_rate = QAM_AUTO;
+ c->symbol_rate = 0;
c->code_rate_HP = FEC_AUTO;
c->code_rate_LP = FEC_AUTO;
-
- c->isdbt_partial_reception = -1;
- c->isdbt_sb_mode = -1;
- c->isdbt_sb_subchannel = -1;
- c->isdbt_sb_segment_idx = -1;
- c->isdbt_sb_segment_count = -1;
- c->isdbt_layer_enabled = 0x7;
+ c->fec_inner = FEC_AUTO;
+ c->rolloff = ROLLOFF_AUTO;
+ c->voltage = SEC_VOLTAGE_OFF;
+ c->sectone = SEC_TONE_OFF;
+ c->pilot = PILOT_AUTO;
+
+ c->isdbt_partial_reception = 0;
+ c->isdbt_sb_mode = 0;
+ c->isdbt_sb_subchannel = 0;
+ c->isdbt_sb_segment_idx = 0;
+ c->isdbt_sb_segment_count = 0;
+ c->isdbt_layer_enabled = 0;
for (i = 0; i < 3; i++) {
c->layer[i].fec = FEC_AUTO;
c->layer[i].modulation = QAM_AUTO;
- c->layer[i].interleaving = -1;
- c->layer[i].segment_count = -1;
+ c->layer[i].interleaving = 0;
+ c->layer[i].segment_count = 0;
+ }
+
+ c->isdbs_ts_id = 0;
+ c->dvbt2_plp_id = 0;
+
+ switch (c->delivery_system) {
+ case SYS_DVBS:
+ case SYS_DVBS2:
+ case SYS_TURBO:
+ c->modulation = QPSK; /* implied for DVB-S in legacy API */
+ c->rolloff = ROLLOFF_35;/* implied for DVB-S */
+ break;
+ case SYS_ATSC:
+ c->modulation = VSB_8;
+ break;
+ default:
+ c->modulation = QAM_AUTO;
+ break;
}
return 0;
@@ -943,25 +1017,6 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
_DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
- _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 0, 0),
- _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 0, 0),
- _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 0, 0),
- _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 0, 0),
- _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0),
-
_DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
_DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
@@ -973,6 +1028,8 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),
_DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),
_DTV_CMD(DTV_HIERARCHY, 0, 0),
+
+ _DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
};
static void dtv_property_dump(struct dtv_property *tvp)
@@ -1006,70 +1063,54 @@ static void dtv_property_dump(struct dtv_property *tvp)
dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
}
-static int is_legacy_delivery_system(fe_delivery_system_t s)
-{
- if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||
- (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) ||
- (s == SYS_ATSC))
- return 1;
-
- return 0;
-}
-
-/* Initialize the cache with some default values derived from the
- * legacy frontend_info structure.
- */
-static void dtv_property_cache_init(struct dvb_frontend *fe,
- struct dtv_frontend_properties *c)
-{
- switch (fe->ops.info.type) {
- case FE_QPSK:
- c->modulation = QPSK; /* implied for DVB-S in legacy API */
- c->rolloff = ROLLOFF_35;/* implied for DVB-S */
- c->delivery_system = SYS_DVBS;
- break;
- case FE_QAM:
- c->delivery_system = SYS_DVBC_ANNEX_AC;
- break;
- case FE_OFDM:
- c->delivery_system = SYS_DVBT;
- break;
- case FE_ATSC:
- break;
- }
-}
-
/* Synchronise the legacy tuning parameters into the cache, so that demodulator
* drivers can use a single set_frontend tuning function, regardless of whether
* it's being used for the legacy or new API, reducing code and complexity.
*/
-static void dtv_property_cache_sync(struct dvb_frontend *fe,
- struct dtv_frontend_properties *c,
- const struct dvb_frontend_parameters *p)
+static int dtv_property_cache_sync(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c,
+ const struct dvb_frontend_parameters *p)
{
c->frequency = p->frequency;
c->inversion = p->inversion;
- switch (fe->ops.info.type) {
- case FE_QPSK:
+ switch (dvbv3_type(c->delivery_system)) {
+ case DVBV3_QPSK:
+ dprintk("%s() Preparing QPSK req\n", __func__);
c->symbol_rate = p->u.qpsk.symbol_rate;
c->fec_inner = p->u.qpsk.fec_inner;
break;
- case FE_QAM:
+ case DVBV3_QAM:
+ dprintk("%s() Preparing QAM req\n", __func__);
c->symbol_rate = p->u.qam.symbol_rate;
c->fec_inner = p->u.qam.fec_inner;
c->modulation = p->u.qam.modulation;
break;
- case FE_OFDM:
- if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
- c->bandwidth_hz = 6000000;
- else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
- c->bandwidth_hz = 7000000;
- else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+ case DVBV3_OFDM:
+ dprintk("%s() Preparing OFDM req\n", __func__);
+ switch (p->u.ofdm.bandwidth) {
+ case BANDWIDTH_10_MHZ:
+ c->bandwidth_hz = 10000000;
+ break;
+ case BANDWIDTH_8_MHZ:
c->bandwidth_hz = 8000000;
- else
- /* Including BANDWIDTH_AUTO */
+ break;
+ case BANDWIDTH_7_MHZ:
+ c->bandwidth_hz = 7000000;
+ break;
+ case BANDWIDTH_6_MHZ:
+ c->bandwidth_hz = 6000000;
+ break;
+ case BANDWIDTH_5_MHZ:
+ c->bandwidth_hz = 5000000;
+ break;
+ case BANDWIDTH_1_712_MHZ:
+ c->bandwidth_hz = 1712000;
+ break;
+ case BANDWIDTH_AUTO:
c->bandwidth_hz = 0;
+ }
+
c->code_rate_HP = p->u.ofdm.code_rate_HP;
c->code_rate_LP = p->u.ofdm.code_rate_LP;
c->modulation = p->u.ofdm.constellation;
@@ -1077,50 +1118,78 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
c->guard_interval = p->u.ofdm.guard_interval;
c->hierarchy = p->u.ofdm.hierarchy_information;
break;
- case FE_ATSC:
+ case DVBV3_ATSC:
+ dprintk("%s() Preparing ATSC req\n", __func__);
c->modulation = p->u.vsb.modulation;
if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
c->delivery_system = SYS_ATSC;
else
c->delivery_system = SYS_DVBC_ANNEX_B;
break;
+ case DVBV3_UNKNOWN:
+ printk(KERN_ERR
+ "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+ __func__, c->delivery_system);
+ return -EINVAL;
}
+
+ return 0;
}
/* Ensure the cached values are set correctly in the frontend
* legacy tuning structures, for the advanced tuning API.
*/
-static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- struct dvb_frontend_parameters *p = &fepriv->parameters_in;
p->frequency = c->frequency;
p->inversion = c->inversion;
- switch (fe->ops.info.type) {
- case FE_QPSK:
+ switch (dvbv3_type(c->delivery_system)) {
+ case DVBV3_UNKNOWN:
+ printk(KERN_ERR
+ "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+ __func__, c->delivery_system);
+ return -EINVAL;
+ case DVBV3_QPSK:
dprintk("%s() Preparing QPSK req\n", __func__);
p->u.qpsk.symbol_rate = c->symbol_rate;
p->u.qpsk.fec_inner = c->fec_inner;
break;
- case FE_QAM:
+ case DVBV3_QAM:
dprintk("%s() Preparing QAM req\n", __func__);
p->u.qam.symbol_rate = c->symbol_rate;
p->u.qam.fec_inner = c->fec_inner;
p->u.qam.modulation = c->modulation;
break;
- case FE_OFDM:
+ case DVBV3_OFDM:
dprintk("%s() Preparing OFDM req\n", __func__);
- if (c->bandwidth_hz == 6000000)
- p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
- else if (c->bandwidth_hz == 7000000)
- p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
- else if (c->bandwidth_hz == 8000000)
+
+ switch (c->bandwidth_hz) {
+ case 10000000:
+ p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ;
+ break;
+ case 8000000:
p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
- else
+ break;
+ case 7000000:
+ p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ break;
+ case 6000000:
+ p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ break;
+ case 5000000:
+ p->u.ofdm.bandwidth = BANDWIDTH_5_MHZ;
+ break;
+ case 1712000:
+ p->u.ofdm.bandwidth = BANDWIDTH_1_712_MHZ;
+ break;
+ case 0:
+ default:
p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+ }
p->u.ofdm.code_rate_HP = c->code_rate_HP;
p->u.ofdm.code_rate_LP = c->code_rate_LP;
p->u.ofdm.constellation = c->modulation;
@@ -1128,78 +1197,40 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
p->u.ofdm.guard_interval = c->guard_interval;
p->u.ofdm.hierarchy_information = c->hierarchy;
break;
- case FE_ATSC:
+ case DVBV3_ATSC:
dprintk("%s() Preparing VSB req\n", __func__);
p->u.vsb.modulation = c->modulation;
break;
}
+ return 0;
}
-/* Ensure the cached values are set correctly in the frontend
- * legacy tuning structures, for the legacy tuning API.
+/**
+ * dtv_get_frontend - calls a callback for retrieving DTV parameters
+ * @fe: struct dvb_frontend pointer
+ * @c: struct dtv_frontend_properties pointer (DVBv5 cache)
+ * @p_out struct dvb_frontend_parameters pointer (DVBv3 FE struct)
+ *
+ * This routine calls either the DVBv3 or DVBv5 get_frontend call.
+ * If c is not null, it will update the DVBv5 cache struct pointed by it.
+ * If p_out is not null, it will update the DVBv3 params pointed by it.
*/
-static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+static int dtv_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p_out)
{
- const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- struct dvb_frontend_parameters *p = &fepriv->parameters_in;
-
- p->frequency = c->frequency;
- p->inversion = c->inversion;
-
- if (c->delivery_system == SYS_DSS ||
- c->delivery_system == SYS_DVBS ||
- c->delivery_system == SYS_DVBS2 ||
- c->delivery_system == SYS_ISDBS ||
- c->delivery_system == SYS_TURBO) {
- p->u.qpsk.symbol_rate = c->symbol_rate;
- p->u.qpsk.fec_inner = c->fec_inner;
- }
+ int r;
- /* Fake out a generic DVB-T request so we pass validation in the ioctl */
- if ((c->delivery_system == SYS_ISDBT) ||
- (c->delivery_system == SYS_DVBT2)) {
- p->u.ofdm.constellation = QAM_AUTO;
- p->u.ofdm.code_rate_HP = FEC_AUTO;
- p->u.ofdm.code_rate_LP = FEC_AUTO;
- p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
- p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
- p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
- if (c->bandwidth_hz == 8000000)
- p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
- else if (c->bandwidth_hz == 7000000)
- p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
- else if (c->bandwidth_hz == 6000000)
- p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
- else
- p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+ if (fe->ops.get_frontend) {
+ r = fe->ops.get_frontend(fe);
+ if (unlikely(r < 0))
+ return r;
+ if (p_out)
+ dtv_property_legacy_params_sync(fe, p_out);
+ return 0;
}
-}
-static void dtv_property_cache_submit(struct dvb_frontend *fe)
-{
- const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
- /* For legacy delivery systems we don't need the delivery_system to
- * be specified, but we populate the older structures from the cache
- * so we can call set_frontend on older drivers.
- */
- if(is_legacy_delivery_system(c->delivery_system)) {
-
- dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation);
- dtv_property_legacy_params_sync(fe);
-
- } else {
- dprintk("%s() adv, modulation = %d\n", __func__, c->modulation);
-
- /* For advanced delivery systems / modulation types ...
- * we seed the lecacy dvb_frontend_parameters structure
- * so that the sanity checking code later in the IOCTL processing
- * can validate our basic frequency ranges, symbolrates, modulation
- * etc.
- */
- dtv_property_adv_params_sync(fe);
- }
+ /* As everything is in cache, get_frontend fops are always supported */
+ return 0;
}
static int dvb_frontend_ioctl_legacy(struct file *file,
@@ -1208,25 +1239,21 @@ static int dvb_frontend_ioctl_properties(struct file *file,
unsigned int cmd, void *parg);
static int dtv_property_process_get(struct dvb_frontend *fe,
+ const struct dtv_frontend_properties *c,
struct dtv_property *tvp,
struct file *file)
{
- const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- struct dtv_frontend_properties cdetected;
- int r;
-
- /*
- * If the driver implements a get_frontend function, then convert
- * detected parameters to S2API properties.
- */
- if (fe->ops.get_frontend) {
- cdetected = *c;
- dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out);
- c = &cdetected;
- }
+ int r, ncaps;
switch(tvp->cmd) {
+ case DTV_ENUM_DELSYS:
+ ncaps = 0;
+ while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps];
+ ncaps++;
+ }
+ tvp->u.buffer.len = ncaps;
+ break;
case DTV_FREQUENCY:
tvp->u.data = c->frequency;
break;
@@ -1356,14 +1383,168 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
return 0;
}
+static int dtv_set_frontend(struct dvb_frontend *fe);
+
+static bool is_dvbv3_delsys(u32 delsys)
+{
+ bool status;
+
+ status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
+ (delsys == SYS_DVBS) || (delsys == SYS_ATSC);
+
+ return status;
+}
+
+static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
+{
+ int ncaps, i;
+ u32 delsys = SYS_UNDEFINED;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ enum dvbv3_emulation_type type;
+
+ /*
+ * It was reported that some old DVBv5 applications were
+ * filling delivery_system with SYS_UNDEFINED. If this happens,
+ * assume that the application wants to use the first supported
+ * delivery system.
+ */
+ if (c->delivery_system == SYS_UNDEFINED)
+ c->delivery_system = fe->ops.delsys[0];
+
+ if (desired_system == SYS_UNDEFINED) {
+ /*
+ * A DVBv3 call doesn't know what's the desired system.
+ * Also, DVBv3 applications don't know that ops.info->type
+ * could be changed, and they simply dies when it doesn't
+ * match.
+ * So, don't change the current delivery system, as it
+ * may be trying to do the wrong thing, like setting an
+ * ISDB-T frontend as DVB-T. Instead, find the closest
+ * DVBv3 system that matches the delivery system.
+ */
+ if (is_dvbv3_delsys(c->delivery_system)) {
+ dprintk("%s() Using delivery system to %d\n",
+ __func__, c->delivery_system);
+ return 0;
+ }
+ type = dvbv3_type(c->delivery_system);
+ switch (type) {
+ case DVBV3_QPSK:
+ desired_system = SYS_DVBS;
+ break;
+ case DVBV3_QAM:
+ desired_system = SYS_DVBC_ANNEX_A;
+ break;
+ case DVBV3_ATSC:
+ desired_system = SYS_ATSC;
+ break;
+ case DVBV3_OFDM:
+ desired_system = SYS_DVBT;
+ break;
+ default:
+ dprintk("%s(): This frontend doesn't support DVBv3 calls\n",
+ __func__);
+ return -EINVAL;
+ }
+ } else {
+ /*
+ * This is a DVBv5 call. So, it likely knows the supported
+ * delivery systems.
+ */
+
+ /* Check if the desired delivery system is supported */
+ ncaps = 0;
+ while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ if (fe->ops.delsys[ncaps] == desired_system) {
+ c->delivery_system = desired_system;
+ dprintk("%s() Changing delivery system to %d\n",
+ __func__, desired_system);
+ return 0;
+ }
+ ncaps++;
+ }
+ type = dvbv3_type(desired_system);
+
+ /*
+ * The delivery system is not supported. See if it can be
+ * emulated.
+ * The emulation only works if the desired system is one of the
+ * DVBv3 delivery systems
+ */
+ if (!is_dvbv3_delsys(desired_system)) {
+ dprintk("%s() can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Get the last non-DVBv3 delivery system that has the same type
+ * of the desired system
+ */
+ ncaps = 0;
+ while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) &&
+ !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
+ delsys = fe->ops.delsys[ncaps];
+ ncaps++;
+ }
+ /* There's nothing compatible with the desired delivery system */
+ if (delsys == SYS_UNDEFINED) {
+ dprintk("%s() Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n",
+ __func__);
+ return -EINVAL;
+ }
+ c->delivery_system = delsys;
+ }
+
+ /*
+ * The DVBv3 or DVBv5 call is requesting a different system. So,
+ * emulation is needed.
+ *
+ * Emulate newer delivery systems like ISDBT, DVBT and DMBTH
+ * for older DVBv5 applications. The emulation will try to use
+ * the auto mode for most things, and will assume that the desired
+ * delivery system is the last one at the ops.delsys[] array
+ */
+ dprintk("%s() Using delivery system %d emulated as if it were a %d\n",
+ __func__, delsys, desired_system);
+
+ /*
+ * For now, handles ISDB-T calls. More code may be needed here for the
+ * other emulated stuff
+ */
+ if (type == DVBV3_OFDM) {
+ if (c->delivery_system == SYS_ISDBT) {
+ dprintk("%s() Using defaults for SYS_ISDBT\n",
+ __func__);
+ if (!c->bandwidth_hz)
+ c->bandwidth_hz = 6000000;
+
+ c->isdbt_partial_reception = 0;
+ c->isdbt_sb_mode = 0;
+ c->isdbt_sb_subchannel = 0;
+ c->isdbt_sb_segment_idx = 0;
+ c->isdbt_sb_segment_count = 0;
+ c->isdbt_layer_enabled = 0;
+ for (i = 0; i < 3; i++) {
+ c->layer[i].fec = FEC_AUTO;
+ c->layer[i].modulation = QAM_AUTO;
+ c->layer[i].interleaving = 0;
+ c->layer[i].segment_count = 0;
+ }
+ }
+ }
+ dprintk("change delivery system on cache to %d\n", c->delivery_system);
+
+ return 0;
+}
+
static int dtv_property_process_set(struct dvb_frontend *fe,
struct dtv_property *tvp,
struct file *file)
{
int r = 0;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct dvb_frontend_private *fepriv = fe->frontend_priv;
- dtv_property_dump(tvp);
/* Allow the frontend to validate incoming properties */
if (fe->ops.set_property) {
@@ -1374,11 +1555,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
switch(tvp->cmd) {
case DTV_CLEAR:
- /* Reset a cache of data specific to the frontend here. This does
+ /*
+ * Reset a cache of data specific to the frontend here. This does
* not effect hardware.
*/
dvb_frontend_clear_cache(fe);
- dprintk("%s() Flushing property cache\n", __func__);
break;
case DTV_TUNE:
/* interpret the cache of data, build either a traditional frontend
@@ -1387,10 +1568,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
*/
c->state = tvp->cmd;
dprintk("%s() Finalised property cache\n", __func__);
- dtv_property_cache_submit(fe);
- r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
- &fepriv->parameters_in);
+ r = dtv_set_frontend(fe);
break;
case DTV_FREQUENCY:
c->frequency = tvp->u.data;
@@ -1417,7 +1596,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
c->rolloff = tvp->u.data;
break;
case DTV_DELIVERY_SYSTEM:
- c->delivery_system = tvp->u.data;
+ r = set_delivery_system(fe, tvp->u.data);
break;
case DTV_VOLTAGE:
c->voltage = tvp->u.data;
@@ -1551,6 +1730,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend *fe = dvbdev->priv;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int err = 0;
@@ -1594,7 +1774,6 @@ static int dvb_frontend_ioctl_properties(struct file *file,
} else
if(cmd == FE_GET_PROPERTY) {
-
tvps = (struct dtv_properties __user *)parg;
dprintk("%s() properties.num = %d\n", __func__, tvps->num);
@@ -1616,8 +1795,18 @@ static int dvb_frontend_ioctl_properties(struct file *file,
goto out;
}
+ /*
+ * Fills the cache out struct with the cache contents, plus
+ * the data retrieved from get_frontend, if the frontend
+ * is not idle. Otherwise, returns the cached content
+ */
+ if (fepriv->state != FESTATE_IDLE) {
+ err = dtv_get_frontend(fe, NULL);
+ if (err < 0)
+ goto out;
+ }
for (i = 0; i < tvps->num; i++) {
- err = dtv_property_process_get(fe, tvp + i, file);
+ err = dtv_property_process_get(fe, c, tvp + i, file);
if (err < 0)
goto out;
(tvp + i)->result = err;
@@ -1636,12 +1825,128 @@ out:
return err;
}
+static int dtv_set_frontend(struct dvb_frontend *fe)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct dvb_frontend_tune_settings fetunesettings;
+ u32 rolloff = 0;
+
+ if (dvb_frontend_check_parameters(fe) < 0)
+ return -EINVAL;
+
+ /*
+ * Initialize output parameters to match the values given by
+ * the user. FE_SET_FRONTEND triggers an initial frontend event
+ * with status = 0, which copies output parameters to userspace.
+ */
+ dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
+
+ /*
+ * Be sure that the bandwidth will be filled for all
+ * non-satellite systems, as tuners need to know what
+ * low pass/Nyquist half filter should be applied, in
+ * order to avoid inter-channel noise.
+ *
+ * ISDB-T and DVB-T/T2 already sets bandwidth.
+ * ATSC and DVB-C don't set, so, the core should fill it.
+ *
+ * On DVB-C Annex A and C, the bandwidth is a function of
+ * the roll-off and symbol rate. Annex B defines different
+ * roll-off factors depending on the modulation. Fortunately,
+ * Annex B is only used with 6MHz, so there's no need to
+ * calculate it.
+ *
+ * While not officially supported, a side effect of handling it at
+ * the cache level is that a program could retrieve the bandwidth
+ * via DTV_BANDWIDTH_HZ, which may be useful for test programs.
+ */
+ switch (c->delivery_system) {
+ case SYS_ATSC:
+ case SYS_DVBC_ANNEX_B:
+ c->bandwidth_hz = 6000000;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ rolloff = 115;
+ break;
+ case SYS_DVBC_ANNEX_C:
+ rolloff = 113;
+ break;
+ default:
+ break;
+ }
+ if (rolloff)
+ c->bandwidth_hz = (c->symbol_rate * rolloff) / 100;
+
+ /* force auto frequency inversion if requested */
+ if (dvb_force_auto_inversion)
+ c->inversion = INVERSION_AUTO;
+
+ /*
+ * without hierarchical coding code_rate_LP is irrelevant,
+ * so we tolerate the otherwise invalid FEC_NONE setting
+ */
+ if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE)
+ c->code_rate_LP = FEC_AUTO;
+
+ /* get frontend-specific tuning settings */
+ memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
+ if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
+ fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
+ fepriv->max_drift = fetunesettings.max_drift;
+ fepriv->step_size = fetunesettings.step_size;
+ } else {
+ /* default values */
+ switch (c->delivery_system) {
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
+ fepriv->min_delay = HZ / 20;
+ fepriv->step_size = c->symbol_rate / 16000;
+ fepriv->max_drift = c->symbol_rate / 2000;
+ break;
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ case SYS_ISDBT:
+ case SYS_DMBTH:
+ fepriv->min_delay = HZ / 20;
+ fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
+ fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+ break;
+ default:
+ /*
+ * FIXME: This sounds wrong! if freqency_stepsize is
+ * defined by the frontend, why not use it???
+ */
+ fepriv->min_delay = HZ / 20;
+ fepriv->step_size = 0; /* no zigzag */
+ fepriv->max_drift = 0;
+ break;
+ }
+ }
+ if (dvb_override_tune_delay > 0)
+ fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
+
+ fepriv->state = FESTATE_RETUNE;
+
+ /* Request the search algorithm to search */
+ fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+
+ dvb_frontend_clear_events(fe);
+ dvb_frontend_add_event(fe, 0);
+ dvb_frontend_wakeup(fe);
+ fepriv->status = 0;
+
+ return 0;
+}
+
+
static int dvb_frontend_ioctl_legacy(struct file *file,
unsigned int cmd, void *parg)
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend *fe = dvbdev->priv;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int cb_err, err = -EOPNOTSUPP;
if (fe->dvb->fe_ioctl_override) {
@@ -1658,9 +1963,43 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
switch (cmd) {
case FE_GET_INFO: {
struct dvb_frontend_info* info = parg;
+
memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);
+ /*
+ * Associate the 4 delivery systems supported by DVBv3
+ * API with their DVBv5 counterpart. For the other standards,
+ * use the closest type, assuming that it would hopefully
+ * work with a DVBv3 application.
+ * It should be noticed that, on multi-frontend devices with
+ * different types (terrestrial and cable, for example),
+ * a pure DVBv3 application won't be able to use all delivery
+ * systems. Yet, changing the DVBv5 cache to the other delivery
+ * system should be enough for making it work.
+ */
+ switch (dvbv3_type(c->delivery_system)) {
+ case DVBV3_QPSK:
+ info->type = FE_QPSK;
+ break;
+ case DVBV3_ATSC:
+ info->type = FE_ATSC;
+ break;
+ case DVBV3_QAM:
+ info->type = FE_QAM;
+ break;
+ case DVBV3_OFDM:
+ info->type = FE_OFDM;
+ break;
+ default:
+ printk(KERN_ERR
+ "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+ __func__, c->delivery_system);
+ fe->ops.info.type = FE_OFDM;
+ }
+ dprintk("current delivery system on cache: %d, V3 type: %d\n",
+ c->delivery_system, fe->ops.info.type);
+
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
info->caps |= FE_CAN_INVERSION_AUTO;
@@ -1819,108 +2158,22 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
break;
- case FE_SET_FRONTEND: {
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct dvb_frontend_tune_settings fetunesettings;
-
- if (c->state == DTV_TUNE) {
- if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) {
- err = -EINVAL;
- break;
- }
- } else {
- if (dvb_frontend_check_parameters(fe, parg) < 0) {
- err = -EINVAL;
- break;
- }
-
- memcpy (&fepriv->parameters_in, parg,
- sizeof (struct dvb_frontend_parameters));
- dtv_property_cache_init(fe, c);
- dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
- }
-
- /*
- * Initialize output parameters to match the values given by
- * the user. FE_SET_FRONTEND triggers an initial frontend event
- * with status = 0, which copies output parameters to userspace.
- */
- fepriv->parameters_out = fepriv->parameters_in;
-
- memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
- memcpy(&fetunesettings.parameters, parg,
- sizeof (struct dvb_frontend_parameters));
-
- /* force auto frequency inversion if requested */
- if (dvb_force_auto_inversion) {
- fepriv->parameters_in.inversion = INVERSION_AUTO;
- fetunesettings.parameters.inversion = INVERSION_AUTO;
- }
- if (fe->ops.info.type == FE_OFDM) {
- /* without hierarchical coding code_rate_LP is irrelevant,
- * so we tolerate the otherwise invalid FEC_NONE setting */
- if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
- fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE)
- fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO;
- }
-
- /* get frontend-specific tuning settings */
- if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
- fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
- fepriv->max_drift = fetunesettings.max_drift;
- fepriv->step_size = fetunesettings.step_size;
- } else {
- /* default values */
- switch(fe->ops.info.type) {
- case FE_QPSK:
- fepriv->min_delay = HZ/20;
- fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000;
- fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000;
- break;
-
- case FE_QAM:
- fepriv->min_delay = HZ/20;
- fepriv->step_size = 0; /* no zigzag */
- fepriv->max_drift = 0;
- break;
-
- case FE_OFDM:
- fepriv->min_delay = HZ/20;
- fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
- fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
- break;
- case FE_ATSC:
- fepriv->min_delay = HZ/20;
- fepriv->step_size = 0;
- fepriv->max_drift = 0;
- break;
- }
- }
- if (dvb_override_tune_delay > 0)
- fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
-
- fepriv->state = FESTATE_RETUNE;
-
- /* Request the search algorithm to search */
- fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+ case FE_SET_FRONTEND:
+ err = set_delivery_system(fe, SYS_UNDEFINED);
+ if (err)
+ break;
- dvb_frontend_clear_events(fe);
- dvb_frontend_add_event(fe, 0);
- dvb_frontend_wakeup(fe);
- fepriv->status = 0;
- err = 0;
+ err = dtv_property_cache_sync(fe, c, parg);
+ if (err)
+ break;
+ err = dtv_set_frontend(fe);
break;
- }
-
case FE_GET_EVENT:
err = dvb_frontend_get_event (fe, parg, file->f_flags);
break;
case FE_GET_FRONTEND:
- if (fe->ops.get_frontend) {
- err = fe->ops.get_frontend(fe, &fepriv->parameters_out);
- memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters));
- }
+ err = dtv_get_frontend(fe, parg);
break;
case FE_SET_FRONTEND_TUNE_MODE:
@@ -2061,12 +2314,15 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
dprintk ("%s\n", __func__);
- if ((file->f_flags & O_ACCMODE) != O_RDONLY)
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
fepriv->release_jiffies = jiffies;
+ mb();
+ }
ret = dvb_generic_release (inode, file);
if (dvbdev->users == -1) {
+ wake_up(&fepriv->wait_queue);
if (fepriv->exit != DVB_FE_NO_EXIT) {
fops_put(file->f_op);
file->f_op = NULL;
@@ -2127,6 +2383,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND);
+ /*
+ * Initialize the cache to the proper values according with the
+ * first supported delivery system (ops->delsys[0])
+ */
+
+ fe->dtv_property_cache.delivery_system = fe->ops.delsys[0];
+ dvb_frontend_clear_cache(fe);
+
mutex_unlock(&frontend_mutex);
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 67bbfa728016..d63a8215fe03 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -42,11 +42,16 @@
#include "dvbdev.h"
+/*
+ * Maximum number of Delivery systems per frontend. It
+ * should be smaller or equal to 32
+ */
+#define MAX_DELSYS 8
+
struct dvb_frontend_tune_settings {
int min_delay_ms;
int step_size;
int max_drift;
- struct dvb_frontend_parameters parameters;
};
struct dvb_frontend;
@@ -198,11 +203,11 @@ struct dvb_tuner_ops {
int (*sleep)(struct dvb_frontend *fe);
/** This is for simple PLLs - set all parameters in one go. */
- int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+ int (*set_params)(struct dvb_frontend *fe);
int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
- int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
+ int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
/** This is to allow setting tuner-specific configs */
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
@@ -250,10 +255,14 @@ struct analog_demod_ops {
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
};
+struct dtv_frontend_properties;
+
struct dvb_frontend_ops {
struct dvb_frontend_info info;
+ u8 delsys[MAX_DELSYS];
+
void (*release)(struct dvb_frontend* fe);
void (*release_sec)(struct dvb_frontend* fe);
@@ -264,7 +273,7 @@ struct dvb_frontend_ops {
/* if this is set, it overrides the default swzigzag */
int (*tune)(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params,
+ bool re_tune,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status);
@@ -272,10 +281,10 @@ struct dvb_frontend_ops {
enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
/* these two are only used for the swzigzag code */
- int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+ int (*set_frontend)(struct dvb_frontend *fe);
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
- int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+ int (*get_frontend)(struct dvb_frontend *fe);
int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
int (*read_ber)(struct dvb_frontend* fe, u32* ber);
@@ -297,8 +306,7 @@ struct dvb_frontend_ops {
/* These callbacks are for devices that implement their own
* tuning algorithms, rather than a simple swzigzag
*/
- enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
- int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+ enum dvbfe_search (*search)(struct dvb_frontend *fe);
struct dvb_tuner_ops tuner_ops;
struct analog_demod_ops analog_ops;
@@ -307,6 +315,7 @@ struct dvb_frontend_ops {
int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
};
+#ifdef __DVB_CORE__
#define MAX_EVENT 8
struct dvb_fe_events {
@@ -317,6 +326,7 @@ struct dvb_fe_events {
wait_queue_head_t wait_queue;
struct mutex mtx;
};
+#endif
struct dtv_frontend_properties {
@@ -374,6 +384,7 @@ struct dvb_frontend {
void *analog_demod_priv;
struct dtv_frontend_properties dtv_property_cache;
#define DVB_FRONTEND_COMPONENT_TUNER 0
+#define DVB_FRONTEND_COMPONENT_DEMOD 1
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
int id;
};
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 93d9869e0f15..8766ce8c354d 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1510,9 +1510,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
for (i=0; i<DVB_NET_DEVICES_MAX; i++)
dvbnet->state[i] = 0;
- dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net,
+ return dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net,
dvbnet, DVB_DEVICE_NET);
-
- return 0;
}
EXPORT_SYMBOL(dvb_net_init);
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 58257165761e..63bf45679f98 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -311,6 +311,7 @@ config DVB_USB_ANYSEE
select DVB_STV0900 if !DVB_FE_CUSTOMISE
select DVB_STV6110 if !DVB_FE_CUSTOMISE
select DVB_ISL6423 if !DVB_FE_CUSTOMISE
+ select DVB_CXD2820R if !DVB_FE_CUSTOMISE
help
Say Y here to support the Anysee E30, Anysee E30 Plus or
Anysee E30 C Plus DVB USB2.0 receiver.
@@ -340,7 +341,7 @@ config DVB_USB_AF9015
config DVB_USB_CE6230
tristate "Intel CE6230 DVB-T USB2.0 support"
- depends on DVB_USB && EXPERIMENTAL
+ depends on DVB_USB
select DVB_ZL10353
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
help
@@ -354,12 +355,20 @@ config DVB_USB_FRIIO
config DVB_USB_EC168
tristate "E3C EC168 DVB-T USB2.0 support"
- depends on DVB_USB && EXPERIMENTAL
+ depends on DVB_USB
select DVB_EC100
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
+config DVB_USB_AZ6007
+ tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
+ depends on DVB_USB
+ select DVB_DRXK if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support theAfatech AF9005 based DVB-T/DVB-C receivers.
+
config DVB_USB_AZ6027
tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
depends on DVB_USB
@@ -377,6 +386,7 @@ config DVB_USB_LME2510
select DVB_IX2505V if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_PLL if !DVB_FE_CUSTOMISE
+ select DVB_M88RS2000 if !DVB_FE_CUSTOMISE
help
Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
@@ -402,3 +412,13 @@ config DVB_USB_MXL111SF
select VIDEO_TVEEPROM
help
Say Y here to support the MxL111SF USB2.0 DTV receiver.
+
+config DVB_USB_RTL28XXU
+ tristate "Realtek RTL28xxU DVB USB support"
+ depends on DVB_USB && EXPERIMENTAL
+ select DVB_RTL2830
+ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the Realtek RTL28xxU DVB USB receiver.
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 26c8b9e57050..b76acb5387e6 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -54,7 +54,6 @@ obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
dvb-usb-opera-objs = opera1.o
obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
-
dvb-usb-af9005-objs = af9005.o af9005-fe.o
obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
@@ -88,6 +87,9 @@ obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
dvb-usb-ec168-objs = ec168.o
obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
+dvb-usb-az6007-objs = az6007.o
+obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o
+
dvb-usb-az6027-objs = az6027.o
obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
@@ -105,8 +107,12 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o
obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o
obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+dvb-usb-rtl28xxu-objs = rtl28xxu.o
+obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
# due to tuner-xc3028
-ccflags-y += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci
diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c
index 3263e9749d09..740f3f496f12 100644
--- a/drivers/media/dvb/dvb-usb/af9005-fe.c
+++ b/drivers/media/dvb/dvb-usb/af9005-fe.c
@@ -303,7 +303,7 @@ static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
return -EINVAL;
}
- /* read constellation mode */
+ /* read modulation mode */
ret =
af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
reg_tpsd_const_pos, reg_tpsd_const_len,
@@ -321,7 +321,7 @@ static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
bits = 6;
break;
default:
- err("invalid constellation mode");
+ err("invalid modulation mode");
return -EINVAL;
}
*pre_bit_count = super_frame_count * 68 * 4 * x * bits;
@@ -533,13 +533,13 @@ static int af9005_fe_read_signal_strength(struct dvb_frontend *fe,
static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr)
{
- /* the snr can be derived from the ber and the constellation
+ /* the snr can be derived from the ber and the modulation
but I don't think this kind of complex calculations belong
in the driver. I may be wrong.... */
return -ENOSYS;
}
-static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
+static int af9005_fe_program_cfoe(struct dvb_usb_device *d, u32 bw)
{
u8 temp0, temp1, temp2, temp3, buf[4];
int ret;
@@ -551,7 +551,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
u32 NS_coeff2_8k;
switch (bw) {
- case BANDWIDTH_6_MHZ:
+ case 6000000:
NS_coeff1_2048Nu = 0x2ADB6DC;
NS_coeff1_8191Nu = 0xAB7313;
NS_coeff1_8192Nu = 0xAB6DB7;
@@ -560,7 +560,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
NS_coeff2_8k = 0x55B6DC;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
NS_coeff1_2048Nu = 0x3200001;
NS_coeff1_8191Nu = 0xC80640;
NS_coeff1_8192Nu = 0xC80000;
@@ -569,7 +569,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
NS_coeff2_8k = 0x640000;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
NS_coeff1_2048Nu = 0x3924926;
NS_coeff1_8191Nu = 0xE4996E;
NS_coeff1_8192Nu = 0xE49249;
@@ -773,17 +773,17 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
}
-static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw)
+static int af9005_fe_select_bw(struct dvb_usb_device *d, u32 bw)
{
u8 temp;
switch (bw) {
- case BANDWIDTH_6_MHZ:
+ case 6000000:
temp = 0;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
temp = 1;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
temp = 2;
break;
default:
@@ -930,10 +930,11 @@ static int af9005_fe_init(struct dvb_frontend *fe)
/* init other parameters: program cfoe and select bandwidth */
deb_info("program cfoe\n");
- if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ)))
+ ret = af9005_fe_program_cfoe(state->d, 6000000);
+ if (ret)
return ret;
- /* set read-update bit for constellation */
- deb_info("set read-update bit for constellation\n");
+ /* set read-update bit for modulation */
+ deb_info("set read-update bit for modulation\n");
if ((ret =
af9005_write_register_bits(state->d, xd_p_reg_feq_read_update,
reg_feq_read_update_pos,
@@ -943,8 +944,8 @@ static int af9005_fe_init(struct dvb_frontend *fe)
/* sample code has a set MPEG TS code here
but sniffing reveals that it doesn't do it */
- /* set read-update bit to 1 for DCA constellation */
- deb_info("set read-update bit 1 for DCA constellation\n");
+ /* set read-update bit to 1 for DCA modulation */
+ deb_info("set read-update bit 1 for DCA modulation\n");
if ((ret =
af9005_write_register_bits(state->d, xd_p_reg_dca_read_update,
reg_dca_read_update_pos,
@@ -1099,15 +1100,15 @@ static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
return 0;
}
-static int af9005_fe_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int af9005_fe_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct af9005_fe_state *state = fe->demodulator_priv;
int ret;
u8 temp, temp0, temp1, temp2;
deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency,
- fep->u.ofdm.bandwidth);
+ fep->bandwidth_hz);
if (fe->ops.tuner_ops.release == NULL) {
err("Tuner not attached");
return -ENODEV;
@@ -1167,10 +1168,10 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe,
/* select bandwidth */
deb_info("select bandwidth");
- ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth);
+ ret = af9005_fe_select_bw(state->d, fep->bandwidth_hz);
if (ret)
return ret;
- ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth);
+ ret = af9005_fe_program_cfoe(state->d, fep->bandwidth_hz);
if (ret)
return ret;
@@ -1189,7 +1190,7 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe,
return ret;
/* set tuner */
deb_info("set tuner\n");
- ret = fe->ops.tuner_ops.set_params(fe, fep);
+ ret = fe->ops.tuner_ops.set_params(fe);
if (ret)
return ret;
@@ -1225,9 +1226,9 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe,
return 0;
}
-static int af9005_fe_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int af9005_fe_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct af9005_fe_state *state = fe->demodulator_priv;
int ret;
u8 temp;
@@ -1239,19 +1240,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
&temp);
if (ret)
return ret;
- deb_info("===== fe_get_frontend ==============\n");
+ deb_info("===== fe_get_frontend_legacy = =============\n");
deb_info("CONSTELLATION ");
switch (temp) {
case 0:
- fep->u.ofdm.constellation = QPSK;
+ fep->modulation = QPSK;
deb_info("QPSK\n");
break;
case 1:
- fep->u.ofdm.constellation = QAM_16;
+ fep->modulation = QAM_16;
deb_info("QAM_16\n");
break;
case 2:
- fep->u.ofdm.constellation = QAM_64;
+ fep->modulation = QAM_64;
deb_info("QAM_64\n");
break;
}
@@ -1266,19 +1267,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
deb_info("HIERARCHY ");
switch (temp) {
case 0:
- fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ fep->hierarchy = HIERARCHY_NONE;
deb_info("NONE\n");
break;
case 1:
- fep->u.ofdm.hierarchy_information = HIERARCHY_1;
+ fep->hierarchy = HIERARCHY_1;
deb_info("1\n");
break;
case 2:
- fep->u.ofdm.hierarchy_information = HIERARCHY_2;
+ fep->hierarchy = HIERARCHY_2;
deb_info("2\n");
break;
case 3:
- fep->u.ofdm.hierarchy_information = HIERARCHY_4;
+ fep->hierarchy = HIERARCHY_4;
deb_info("4\n");
break;
}
@@ -1302,23 +1303,23 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
deb_info("CODERATE HP ");
switch (temp) {
case 0:
- fep->u.ofdm.code_rate_HP = FEC_1_2;
+ fep->code_rate_HP = FEC_1_2;
deb_info("FEC_1_2\n");
break;
case 1:
- fep->u.ofdm.code_rate_HP = FEC_2_3;
+ fep->code_rate_HP = FEC_2_3;
deb_info("FEC_2_3\n");
break;
case 2:
- fep->u.ofdm.code_rate_HP = FEC_3_4;
+ fep->code_rate_HP = FEC_3_4;
deb_info("FEC_3_4\n");
break;
case 3:
- fep->u.ofdm.code_rate_HP = FEC_5_6;
+ fep->code_rate_HP = FEC_5_6;
deb_info("FEC_5_6\n");
break;
case 4:
- fep->u.ofdm.code_rate_HP = FEC_7_8;
+ fep->code_rate_HP = FEC_7_8;
deb_info("FEC_7_8\n");
break;
}
@@ -1333,23 +1334,23 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
deb_info("CODERATE LP ");
switch (temp) {
case 0:
- fep->u.ofdm.code_rate_LP = FEC_1_2;
+ fep->code_rate_LP = FEC_1_2;
deb_info("FEC_1_2\n");
break;
case 1:
- fep->u.ofdm.code_rate_LP = FEC_2_3;
+ fep->code_rate_LP = FEC_2_3;
deb_info("FEC_2_3\n");
break;
case 2:
- fep->u.ofdm.code_rate_LP = FEC_3_4;
+ fep->code_rate_LP = FEC_3_4;
deb_info("FEC_3_4\n");
break;
case 3:
- fep->u.ofdm.code_rate_LP = FEC_5_6;
+ fep->code_rate_LP = FEC_5_6;
deb_info("FEC_5_6\n");
break;
case 4:
- fep->u.ofdm.code_rate_LP = FEC_7_8;
+ fep->code_rate_LP = FEC_7_8;
deb_info("FEC_7_8\n");
break;
}
@@ -1363,19 +1364,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
deb_info("GUARD INTERVAL ");
switch (temp) {
case 0:
- fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ fep->guard_interval = GUARD_INTERVAL_1_32;
deb_info("1_32\n");
break;
case 1:
- fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+ fep->guard_interval = GUARD_INTERVAL_1_16;
deb_info("1_16\n");
break;
case 2:
- fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+ fep->guard_interval = GUARD_INTERVAL_1_8;
deb_info("1_8\n");
break;
case 3:
- fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+ fep->guard_interval = GUARD_INTERVAL_1_4;
deb_info("1_4\n");
break;
}
@@ -1390,11 +1391,11 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
deb_info("TRANSMISSION MODE ");
switch (temp) {
case 0:
- fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+ fep->transmission_mode = TRANSMISSION_MODE_2K;
deb_info("2K\n");
break;
case 1:
- fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ fep->transmission_mode = TRANSMISSION_MODE_8K;
deb_info("8K\n");
break;
}
@@ -1406,15 +1407,15 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
deb_info("BANDWIDTH ");
switch (temp) {
case 0:
- fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ fep->bandwidth_hz = 6000000;
deb_info("6\n");
break;
case 1:
- fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ fep->bandwidth_hz = 7000000;
deb_info("7\n");
break;
case 2:
- fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ fep->bandwidth_hz = 8000000;
deb_info("8\n");
break;
}
@@ -1454,9 +1455,9 @@ struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d)
}
static struct dvb_frontend_ops af9005_fe_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "AF9005 USB DVB-T",
- .type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 250000,
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
index bd51a764351b..af176b6ce738 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug,
"set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
DVB_USB_DEBUG_STATUS);
/* enable obnoxious led */
-int dvb_usb_af9005_led = 1;
+bool dvb_usb_af9005_led = 1;
module_param_named(led, dvb_usb_af9005_led, bool, 0644);
MODULE_PARM_DESC(led, "enable led (default: 1).");
@@ -977,11 +977,20 @@ static int af9005_usb_probe(struct usb_interface *intf,
THIS_MODULE, NULL, adapter_nr);
}
+enum af9005_usb_table_entry {
+ AFATECH_AF9005,
+ TERRATEC_AF9005,
+ ANSONIC_AF9005,
+};
+
static struct usb_device_id af9005_usb_table[] = {
- {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
- {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
- {USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)},
- {0},
+ [AFATECH_AF9005] = {USB_DEVICE(USB_VID_AFATECH,
+ USB_PID_AFATECH_AF9005)},
+ [TERRATEC_AF9005] = {USB_DEVICE(USB_VID_TERRATEC,
+ USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+ [ANSONIC_AF9005] = {USB_DEVICE(USB_VID_ANSONIC,
+ USB_PID_ANSONIC_DVBT_USB)},
+ { }
};
MODULE_DEVICE_TABLE(usb, af9005_usb_table);
@@ -1041,15 +1050,15 @@ static struct dvb_usb_device_properties af9005_properties = {
.num_device_descs = 3,
.devices = {
{.name = "Afatech DVB-T USB1.1 stick",
- .cold_ids = {&af9005_usb_table[0], NULL},
+ .cold_ids = {&af9005_usb_table[AFATECH_AF9005], NULL},
.warm_ids = {NULL},
},
{.name = "TerraTec Cinergy T USB XE",
- .cold_ids = {&af9005_usb_table[1], NULL},
+ .cold_ids = {&af9005_usb_table[TERRATEC_AF9005], NULL},
.warm_ids = {NULL},
},
{.name = "Ansonic DVB-T USB1.1 stick",
- .cold_ids = {&af9005_usb_table[2], NULL},
+ .cold_ids = {&af9005_usb_table[ANSONIC_AF9005], NULL},
.warm_ids = {NULL},
},
{NULL},
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
index c71c77bd7f4b..6a2bf3de8456 100644
--- a/drivers/media/dvb/dvb-usb/af9005.h
+++ b/drivers/media/dvb/dvb-usb/af9005.h
@@ -35,7 +35,7 @@ extern int dvb_usb_af9005_debug;
#define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args)
#define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args)
-extern int dvb_usb_af9005_led;
+extern bool dvb_usb_af9005_led;
/* firmware */
#define FW_BULKOUT_SIZE 250
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 56cbd3636c31..7e70ea50ef26 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -50,14 +50,14 @@ static int af9015_properties_count = ARRAY_SIZE(af9015_properties);
static struct af9013_config af9015_af9013_config[] = {
{
- .demod_address = AF9015_I2C_DEMOD,
- .output_mode = AF9013_OUTPUT_MODE_USB,
+ .i2c_addr = AF9015_I2C_DEMOD,
+ .ts_mode = AF9013_TS_USB,
.api_version = { 0, 1, 9, 0 },
.gpio[0] = AF9013_GPIO_HI,
.gpio[3] = AF9013_GPIO_TUNER_ON,
}, {
- .output_mode = AF9013_OUTPUT_MODE_SERIAL,
+ .ts_mode = AF9013_TS_SERIAL,
.api_version = { 0, 1, 9, 0 },
.gpio[0] = AF9013_GPIO_TUNER_ON,
.gpio[1] = AF9013_GPIO_LO,
@@ -216,8 +216,8 @@ static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
{
struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
- if (addr == af9015_af9013_config[0].demod_address ||
- addr == af9015_af9013_config[1].demod_address)
+ if (addr == af9015_af9013_config[0].i2c_addr ||
+ addr == af9015_af9013_config[1].i2c_addr)
req.addr_len = 3;
return af9015_ctrl_msg(d, &req);
@@ -228,8 +228,8 @@ static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
{
struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
- if (addr == af9015_af9013_config[0].demod_address ||
- addr == af9015_af9013_config[1].demod_address)
+ if (addr == af9015_af9013_config[0].i2c_addr ||
+ addr == af9015_af9013_config[1].i2c_addr)
req.addr_len = 3;
return af9015_ctrl_msg(d, &req);
@@ -271,8 +271,8 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
return -EAGAIN;
while (i < num) {
- if (msg[i].addr == af9015_af9013_config[0].demod_address ||
- msg[i].addr == af9015_af9013_config[1].demod_address) {
+ if (msg[i].addr == af9015_af9013_config[0].i2c_addr ||
+ msg[i].addr == af9015_af9013_config[1].i2c_addr) {
addr = msg[i].buf[0] << 8;
addr += msg[i].buf[1];
mbox = msg[i].buf[2];
@@ -288,8 +288,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
ret = -EOPNOTSUPP;
goto error;
}
- if (msg[i].addr ==
- af9015_af9013_config[0].demod_address)
+ if (msg[i].addr == af9015_af9013_config[0].i2c_addr)
req.cmd = READ_MEMORY;
else
req.cmd = READ_I2C;
@@ -307,7 +306,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
goto error;
}
if (msg[i].addr ==
- af9015_af9013_config[0].demod_address) {
+ af9015_af9013_config[0].i2c_addr) {
ret = -EINVAL;
goto error;
}
@@ -325,8 +324,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
ret = -EOPNOTSUPP;
goto error;
}
- if (msg[i].addr ==
- af9015_af9013_config[0].demod_address)
+ if (msg[i].addr == af9015_af9013_config[0].i2c_addr)
req.cmd = WRITE_MEMORY;
else
req.cmd = WRITE_I2C;
@@ -508,7 +506,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
msleep(100);
ret = af9015_read_reg_i2c(d,
- af9015_af9013_config[1].demod_address, 0x98be, &val);
+ af9015_af9013_config[1].i2c_addr, 0x98be, &val);
if (ret)
goto error;
else
@@ -536,7 +534,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
goto error;
/* request boot firmware */
- ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address,
+ ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].i2c_addr,
0xe205, 1);
deb_info("%s: firmware boot cmd status:%d\n", __func__, ret);
if (ret)
@@ -547,7 +545,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
/* check firmware status */
ret = af9015_read_reg_i2c(d,
- af9015_af9013_config[1].demod_address, 0x98be, &val);
+ af9015_af9013_config[1].i2c_addr, 0x98be, &val);
deb_info("%s: firmware status cmd status:%d fw status:%02x\n",
__func__, ret, val);
if (ret)
@@ -840,7 +838,7 @@ static int af9015_read_config(struct usb_device *udev)
if (ret)
goto error;
- deb_info("%s: IR mode:%d\n", __func__, val);
+ deb_info("%s: IR mode=%d\n", __func__, val);
for (i = 0; i < af9015_properties_count; i++) {
if (val == AF9015_IR_MODE_DISABLED)
af9015_properties[i].rc.core.rc_codes = NULL;
@@ -854,7 +852,7 @@ static int af9015_read_config(struct usb_device *udev)
if (ret)
goto error;
af9015_config.dual_mode = val;
- deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode);
+ deb_info("%s: TS mode=%d\n", __func__, af9015_config.dual_mode);
/* Set adapter0 buffer size according to USB port speed, adapter1 buffer
size can be static because it is enabled only USB2.0 */
@@ -878,7 +876,7 @@ static int af9015_read_config(struct usb_device *udev)
ret = af9015_rw_udev(udev, &req);
if (ret)
goto error;
- af9015_af9013_config[1].demod_address = val;
+ af9015_af9013_config[1].i2c_addr = val;
/* enable 2nd adapter */
for (i = 0; i < af9015_properties_count; i++)
@@ -900,34 +898,38 @@ static int af9015_read_config(struct usb_device *udev)
goto error;
switch (val) {
case 0:
- af9015_af9013_config[i].adc_clock = 28800;
+ af9015_af9013_config[i].clock = 28800000;
break;
case 1:
- af9015_af9013_config[i].adc_clock = 20480;
+ af9015_af9013_config[i].clock = 20480000;
break;
case 2:
- af9015_af9013_config[i].adc_clock = 28000;
+ af9015_af9013_config[i].clock = 28000000;
break;
case 3:
- af9015_af9013_config[i].adc_clock = 25000;
+ af9015_af9013_config[i].clock = 25000000;
break;
};
- deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i,
- val, af9015_af9013_config[i].adc_clock);
+ deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i,
+ val, af9015_af9013_config[i].clock);
- /* tuner IF */
+ /* IF frequency */
req.addr = AF9015_EEPROM_IF1H + offset;
ret = af9015_rw_udev(udev, &req);
if (ret)
goto error;
- af9015_af9013_config[i].tuner_if = val << 8;
+
+ af9015_af9013_config[i].if_frequency = val << 8;
+
req.addr = AF9015_EEPROM_IF1L + offset;
ret = af9015_rw_udev(udev, &req);
if (ret)
goto error;
- af9015_af9013_config[i].tuner_if += val;
- deb_info("%s: [%d] IF1:%d\n", __func__, i,
- af9015_af9013_config[0].tuner_if);
+
+ af9015_af9013_config[i].if_frequency += val;
+ af9015_af9013_config[i].if_frequency *= 1000;
+ deb_info("%s: [%d] IF frequency=%d\n", __func__, i,
+ af9015_af9013_config[0].if_frequency);
/* MT2060 IF1 */
req.addr = AF9015_EEPROM_MT2060_IF1H + offset;
@@ -940,7 +942,7 @@ static int af9015_read_config(struct usb_device *udev)
if (ret)
goto error;
af9015_config.mt2060_if1[i] += val;
- deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i,
+ deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i,
af9015_config.mt2060_if1[i]);
/* tuner */
@@ -957,30 +959,30 @@ static int af9015_read_config(struct usb_device *udev)
case AF9013_TUNER_TDA18271:
case AF9013_TUNER_QT1010A:
case AF9013_TUNER_TDA18218:
- af9015_af9013_config[i].rf_spec_inv = 1;
+ af9015_af9013_config[i].spec_inv = 1;
break;
case AF9013_TUNER_MXL5003D:
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
case AF9013_TUNER_MXL5007T:
- af9015_af9013_config[i].rf_spec_inv = 0;
+ af9015_af9013_config[i].spec_inv = 0;
break;
case AF9013_TUNER_MC44S803:
af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
- af9015_af9013_config[i].rf_spec_inv = 1;
+ af9015_af9013_config[i].spec_inv = 1;
break;
default:
- warn("tuner id:%d not supported, please report!", val);
+ warn("tuner id=%d not supported, please report!", val);
return -ENODEV;
};
af9015_af9013_config[i].tuner = val;
- deb_info("%s: [%d] tuner id:%d\n", __func__, i, val);
+ deb_info("%s: [%d] tuner id=%d\n", __func__, i, val);
}
error:
if (ret)
- err("eeprom read failed:%d", ret);
+ err("eeprom read failed=%d", ret);
/* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
content :-( Override some wrong values here. Ditto for the
@@ -998,7 +1000,7 @@ error:
af9015_properties[i].num_adapters = 1;
/* set correct IF */
- af9015_af9013_config[0].tuner_if = 4570;
+ af9015_af9013_config[0].if_frequency = 4570000;
}
return ret;
@@ -1093,9 +1095,114 @@ error:
return ret;
}
+/* override demod callbacks for resource locking */
+static int af9015_af9013_set_frontend(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct af9015_state *priv = adap->dev->priv;
+
+ if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+ return -EAGAIN;
+
+ ret = priv->set_frontend[adap->id](fe);
+
+ mutex_unlock(&adap->dev->usb_mutex);
+
+ return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_read_status(struct dvb_frontend *fe,
+ fe_status_t *status)
+{
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct af9015_state *priv = adap->dev->priv;
+
+ if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+ return -EAGAIN;
+
+ ret = priv->read_status[adap->id](fe, status);
+
+ mutex_unlock(&adap->dev->usb_mutex);
+
+ return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_init(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct af9015_state *priv = adap->dev->priv;
+
+ if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+ return -EAGAIN;
+
+ ret = priv->init[adap->id](fe);
+
+ mutex_unlock(&adap->dev->usb_mutex);
+
+ return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_sleep(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct af9015_state *priv = adap->dev->priv;
+
+ if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+ return -EAGAIN;
+
+ ret = priv->sleep[adap->id](fe);
+
+ mutex_unlock(&adap->dev->usb_mutex);
+
+ return ret;
+}
+
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_init(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct af9015_state *priv = adap->dev->priv;
+
+ if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+ return -EAGAIN;
+
+ ret = priv->tuner_init[adap->id](fe);
+
+ mutex_unlock(&adap->dev->usb_mutex);
+
+ return ret;
+}
+
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_sleep(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct af9015_state *priv = adap->dev->priv;
+
+ if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+ return -EAGAIN;
+
+ ret = priv->tuner_sleep[adap->id](fe);
+
+ mutex_unlock(&adap->dev->usb_mutex);
+
+ return ret;
+}
+
+
static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
{
int ret;
+ struct af9015_state *state = adap->dev->priv;
if (adap->id == 1) {
/* copy firmware to 2nd demodulator */
@@ -1116,6 +1223,32 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
&adap->dev->i2c_adap);
+ /*
+ * AF9015 firmware does not like if it gets interrupted by I2C adapter
+ * request on some critical phases. During normal operation I2C adapter
+ * is used only 2nd demodulator and tuner on dual tuner devices.
+ * Override demodulator callbacks and use mutex for limit access to
+ * those "critical" paths to keep AF9015 happy.
+ * Note: we abuse unused usb_mutex here.
+ */
+ if (adap->fe_adap[0].fe) {
+ state->set_frontend[adap->id] =
+ adap->fe_adap[0].fe->ops.set_frontend;
+ adap->fe_adap[0].fe->ops.set_frontend =
+ af9015_af9013_set_frontend;
+
+ state->read_status[adap->id] =
+ adap->fe_adap[0].fe->ops.read_status;
+ adap->fe_adap[0].fe->ops.read_status =
+ af9015_af9013_read_status;
+
+ state->init[adap->id] = adap->fe_adap[0].fe->ops.init;
+ adap->fe_adap[0].fe->ops.init = af9015_af9013_init;
+
+ state->sleep[adap->id] = adap->fe_adap[0].fe->ops.sleep;
+ adap->fe_adap[0].fe->ops.sleep = af9015_af9013_sleep;
+ }
+
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
@@ -1185,6 +1318,7 @@ static struct mxl5007t_config af9015_mxl5007t_config = {
static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
{
int ret;
+ struct af9015_state *state = adap->dev->priv;
deb_info("%s:\n", __func__);
switch (af9015_af9013_config[adap->id].tuner) {
@@ -1242,52 +1376,128 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
err("Unknown tuner id:%d",
af9015_af9013_config[adap->id].tuner);
}
+
+ if (adap->fe_adap[0].fe->ops.tuner_ops.init) {
+ state->tuner_init[adap->id] =
+ adap->fe_adap[0].fe->ops.tuner_ops.init;
+ adap->fe_adap[0].fe->ops.tuner_ops.init = af9015_tuner_init;
+ }
+
+ if (adap->fe_adap[0].fe->ops.tuner_ops.sleep) {
+ state->tuner_sleep[adap->id] =
+ adap->fe_adap[0].fe->ops.tuner_ops.sleep;
+ adap->fe_adap[0].fe->ops.tuner_ops.sleep = af9015_tuner_sleep;
+ }
+
return ret;
}
+enum af9015_usb_table_entry {
+ AFATECH_9015,
+ AFATECH_9016,
+ WINFAST_DTV_GOLD,
+ PINNACLE_PCTV_71E,
+ KWORLD_PLUSTV_399U,
+ TINYTWIN,
+ AZUREWAVE_TU700,
+ TERRATEC_AF9015,
+ KWORLD_PLUSTV_PC160,
+ AVERTV_VOLAR_X,
+ XTENSIONS_380U,
+ MSI_DIGIVOX_DUO,
+ AVERTV_VOLAR_X_REV2,
+ TELESTAR_STARSTICK_2,
+ AVERMEDIA_A309_USB,
+ MSI_DIGIVOX_MINI_III,
+ KWORLD_E396,
+ KWORLD_E39B,
+ KWORLD_E395,
+ TREKSTOR_DVBT,
+ AVERTV_A850,
+ AVERTV_A805,
+ CONCEPTRONIC_CTVDIGRCU,
+ KWORLD_MC810,
+ GENIUS_TVGO_DVB_T03,
+ KWORLD_399U_2,
+ KWORLD_PC160_T,
+ SVEON_STV20,
+ TINYTWIN_2,
+ WINFAST_DTV2000DS,
+ KWORLD_UB383_T,
+ KWORLD_E39A,
+ AVERMEDIA_A815M,
+ CINERGY_T_STICK_RC,
+ CINERGY_T_DUAL_RC,
+ AVERTV_A850T,
+ TINYTWIN_3,
+ SVEON_STV22,
+};
+
static struct usb_device_id af9015_usb_table[] = {
-/* 0 */{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)},
- {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)},
- {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)},
- {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)},
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)},
-/* 5 */{USB_DEVICE(USB_VID_VISIONPLUS,
- USB_PID_TINYTWIN)},
- {USB_DEVICE(USB_VID_VISIONPLUS,
- USB_PID_AZUREWAVE_AD_TU700)},
- {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)},
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)},
- {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
-/* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
- {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)},
- {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
- {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)},
- {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
-/* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
- {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_AFATECH, USB_PID_TREKSTOR_DVBT)},
-/* 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)},
-/* 25 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)},
- {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
-/* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
- {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
- {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
- {USB_DEVICE(USB_VID_TERRATEC,
- USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
-/* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
- {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)},
- {0},
+ [AFATECH_9015] =
+ {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)},
+ [AFATECH_9016] =
+ {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)},
+ [WINFAST_DTV_GOLD] =
+ {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)},
+ [PINNACLE_PCTV_71E] =
+ {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)},
+ [KWORLD_PLUSTV_399U] =
+ {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)},
+ [TINYTWIN] = {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)},
+ [AZUREWAVE_TU700] =
+ {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)},
+ [TERRATEC_AF9015] = {USB_DEVICE(USB_VID_TERRATEC,
+ USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)},
+ [KWORLD_PLUSTV_PC160] =
+ {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)},
+ [AVERTV_VOLAR_X] =
+ {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
+ [XTENSIONS_380U] =
+ {USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
+ [MSI_DIGIVOX_DUO] =
+ {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)},
+ [AVERTV_VOLAR_X_REV2] =
+ {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
+ [TELESTAR_STARSTICK_2] =
+ {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)},
+ [AVERMEDIA_A309_USB] =
+ {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
+ [MSI_DIGIVOX_MINI_III] =
+ {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
+ [KWORLD_E396] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
+ [KWORLD_E39B] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)},
+ [KWORLD_E395] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)},
+ [TREKSTOR_DVBT] = {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)},
+ [AVERTV_A850] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
+ [AVERTV_A805] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
+ [CONCEPTRONIC_CTVDIGRCU] =
+ {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)},
+ [KWORLD_MC810] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
+ [GENIUS_TVGO_DVB_T03] =
+ {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
+ [KWORLD_399U_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
+ [KWORLD_PC160_T] =
+ {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
+ [SVEON_STV20] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
+ [TINYTWIN_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)},
+ [WINFAST_DTV2000DS] =
+ {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
+ [KWORLD_UB383_T] =
+ {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
+ [KWORLD_E39A] =
+ {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
+ [AVERMEDIA_A815M] =
+ {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
+ [CINERGY_T_STICK_RC] = {USB_DEVICE(USB_VID_TERRATEC,
+ USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
+ [CINERGY_T_DUAL_RC] = {USB_DEVICE(USB_VID_TERRATEC,
+ USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
+ [AVERTV_A850T] =
+ {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
+ [TINYTWIN_3] = {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
+ [SVEON_STV22] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)},
+ { }
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1362,68 +1572,104 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.devices = {
{
.name = "Afatech AF9015 DVB-T USB2.0 stick",
- .cold_ids = {&af9015_usb_table[0],
- &af9015_usb_table[1], NULL},
+ .cold_ids = {
+ &af9015_usb_table[AFATECH_9015],
+ &af9015_usb_table[AFATECH_9016],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "Leadtek WinFast DTV Dongle Gold",
- .cold_ids = {&af9015_usb_table[2], NULL},
+ .cold_ids = {
+ &af9015_usb_table[WINFAST_DTV_GOLD],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "Pinnacle PCTV 71e",
- .cold_ids = {&af9015_usb_table[3], NULL},
+ .cold_ids = {
+ &af9015_usb_table[PINNACLE_PCTV_71E],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "KWorld PlusTV Dual DVB-T Stick " \
"(DVB-T 399U)",
- .cold_ids = {&af9015_usb_table[4],
- &af9015_usb_table[25], NULL},
+ .cold_ids = {
+ &af9015_usb_table[KWORLD_PLUSTV_399U],
+ &af9015_usb_table[KWORLD_399U_2],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "DigitalNow TinyTwin DVB-T Receiver",
- .cold_ids = {&af9015_usb_table[5],
- &af9015_usb_table[28],
- &af9015_usb_table[36], NULL},
+ .cold_ids = {
+ &af9015_usb_table[TINYTWIN],
+ &af9015_usb_table[TINYTWIN_2],
+ &af9015_usb_table[TINYTWIN_3],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "TwinHan AzureWave AD-TU700(704J)",
- .cold_ids = {&af9015_usb_table[6], NULL},
+ .cold_ids = {
+ &af9015_usb_table[AZUREWAVE_TU700],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "TerraTec Cinergy T USB XE",
- .cold_ids = {&af9015_usb_table[7], NULL},
+ .cold_ids = {
+ &af9015_usb_table[TERRATEC_AF9015],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "KWorld PlusTV Dual DVB-T PCI " \
"(DVB-T PC160-2T)",
- .cold_ids = {&af9015_usb_table[8], NULL},
+ .cold_ids = {
+ &af9015_usb_table[KWORLD_PLUSTV_PC160],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "AVerMedia AVerTV DVB-T Volar X",
- .cold_ids = {&af9015_usb_table[9], NULL},
+ .cold_ids = {
+ &af9015_usb_table[AVERTV_VOLAR_X],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "TerraTec Cinergy T Stick RC",
- .cold_ids = {&af9015_usb_table[33], NULL},
+ .cold_ids = {
+ &af9015_usb_table[CINERGY_T_STICK_RC],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "TerraTec Cinergy T Stick Dual RC",
- .cold_ids = {&af9015_usb_table[34], NULL},
+ .cold_ids = {
+ &af9015_usb_table[CINERGY_T_DUAL_RC],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "AverMedia AVerTV Red HD+ (A850T)",
- .cold_ids = {&af9015_usb_table[35], NULL},
+ .cold_ids = {
+ &af9015_usb_table[AVERTV_A850T],
+ NULL
+ },
.warm_ids = {NULL},
},
}
@@ -1496,57 +1742,87 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.devices = {
{
.name = "Xtensions XD-380",
- .cold_ids = {&af9015_usb_table[10], NULL},
+ .cold_ids = {
+ &af9015_usb_table[XTENSIONS_380U],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "MSI DIGIVOX Duo",
- .cold_ids = {&af9015_usb_table[11], NULL},
+ .cold_ids = {
+ &af9015_usb_table[MSI_DIGIVOX_DUO],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "Fujitsu-Siemens Slim Mobile USB DVB-T",
- .cold_ids = {&af9015_usb_table[12], NULL},
+ .cold_ids = {
+ &af9015_usb_table[AVERTV_VOLAR_X_REV2],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "Telestar Starstick 2",
- .cold_ids = {&af9015_usb_table[13], NULL},
+ .cold_ids = {
+ &af9015_usb_table[TELESTAR_STARSTICK_2],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "AVerMedia A309",
- .cold_ids = {&af9015_usb_table[14], NULL},
+ .cold_ids = {
+ &af9015_usb_table[AVERMEDIA_A309_USB],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "MSI Digi VOX mini III",
- .cold_ids = {&af9015_usb_table[15], NULL},
+ .cold_ids = {
+ &af9015_usb_table[MSI_DIGIVOX_MINI_III],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "KWorld USB DVB-T TV Stick II " \
"(VS-DVB-T 395U)",
- .cold_ids = {&af9015_usb_table[16],
- &af9015_usb_table[17],
- &af9015_usb_table[18],
- &af9015_usb_table[31], NULL},
+ .cold_ids = {
+ &af9015_usb_table[KWORLD_E396],
+ &af9015_usb_table[KWORLD_E39B],
+ &af9015_usb_table[KWORLD_E395],
+ &af9015_usb_table[KWORLD_E39A],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "TrekStor DVB-T USB Stick",
- .cold_ids = {&af9015_usb_table[19], NULL},
+ .cold_ids = {
+ &af9015_usb_table[TREKSTOR_DVBT],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "AverMedia AVerTV Volar Black HD " \
"(A850)",
- .cold_ids = {&af9015_usb_table[20], NULL},
+ .cold_ids = {
+ &af9015_usb_table[AVERTV_A850],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "Sveon STV22 Dual USB DVB-T Tuner HDTV",
- .cold_ids = {&af9015_usb_table[37], NULL},
+ .cold_ids = {
+ &af9015_usb_table[SVEON_STV22],
+ NULL
+ },
.warm_ids = {NULL},
},
}
@@ -1619,50 +1895,77 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.devices = {
{
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
- .cold_ids = {&af9015_usb_table[21], NULL},
+ .cold_ids = {
+ &af9015_usb_table[AVERTV_A805],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
"V3.0",
- .cold_ids = {&af9015_usb_table[22], NULL},
+ .cold_ids = {
+ &af9015_usb_table[CONCEPTRONIC_CTVDIGRCU],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "KWorld Digial MC-810",
- .cold_ids = {&af9015_usb_table[23], NULL},
+ .cold_ids = {
+ &af9015_usb_table[KWORLD_MC810],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "Genius TVGo DVB-T03",
- .cold_ids = {&af9015_usb_table[24], NULL},
+ .cold_ids = {
+ &af9015_usb_table[GENIUS_TVGO_DVB_T03],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "KWorld PlusTV DVB-T PCI Pro Card " \
"(DVB-T PC160-T)",
- .cold_ids = {&af9015_usb_table[26], NULL},
+ .cold_ids = {
+ &af9015_usb_table[KWORLD_PC160_T],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "Sveon STV20 Tuner USB DVB-T HDTV",
- .cold_ids = {&af9015_usb_table[27], NULL},
+ .cold_ids = {
+ &af9015_usb_table[SVEON_STV20],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "Leadtek WinFast DTV2000DS",
- .cold_ids = {&af9015_usb_table[29], NULL},
+ .cold_ids = {
+ &af9015_usb_table[WINFAST_DTV2000DS],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "KWorld USB DVB-T Stick Mobile " \
"(UB383-T)",
- .cold_ids = {&af9015_usb_table[30], NULL},
+ .cold_ids = {
+ &af9015_usb_table[KWORLD_UB383_T],
+ NULL
+ },
.warm_ids = {NULL},
},
{
.name = "AverMedia AVerTV Volar M (A815Mac)",
- .cold_ids = {&af9015_usb_table[32], NULL},
+ .cold_ids = {
+ &af9015_usb_table[AVERMEDIA_A815M],
+ NULL
+ },
.warm_ids = {NULL},
},
}
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index 6252ea6c1904..2f68419e899b 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -102,6 +102,14 @@ struct af9015_state {
u8 rc_repeat;
u32 rc_keycode;
u8 rc_last[4];
+
+ /* for demod callback override */
+ int (*set_frontend[2]) (struct dvb_frontend *fe);
+ int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status);
+ int (*init[2]) (struct dvb_frontend *fe);
+ int (*sleep[2]) (struct dvb_frontend *fe);
+ int (*tuner_init[2]) (struct dvb_frontend *fe);
+ int (*tuner_sleep[2]) (struct dvb_frontend *fe);
};
struct af9015_config {
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index b39f14f85e71..03c28655af1b 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -41,6 +41,7 @@
#include "stv0900.h"
#include "stv6110.h"
#include "isl6423.h"
+#include "cxd2820r.h"
/* debug */
static int dvb_usb_anysee_debug;
@@ -57,7 +58,7 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
u8 *rbuf, u8 rlen)
{
struct anysee_state *state = d->priv;
- int act_len, ret;
+ int act_len, ret, i;
u8 buf[64];
memcpy(&buf[0], sbuf, slen);
@@ -66,27 +67,58 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
if (mutex_lock_interruptible(&anysee_usb_mutex) < 0)
return -EAGAIN;
+ deb_xfer(">>> ");
+ debug_dump(buf, slen, deb_xfer);
+
/* We need receive one message more after dvb_usb_generic_rw due
to weird transaction flow, which is 1 x send + 2 x receive. */
ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
+ if (ret)
+ goto error_unlock;
+
+ /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32
+ * (EPIPE, Broken pipe). Function supports currently msleep() as a
+ * parameter but I would not like to use it, since according to
+ * Documentation/timers/timers-howto.txt it should not be used such
+ * short, under < 20ms, sleeps. Repeating failed message would be
+ * better choice as not to add unwanted delays...
+ * Fixing that correctly is one of those or both;
+ * 1) use repeat if possible
+ * 2) add suitable delay
+ */
- if (!ret) {
+ /* get answer, retry few times if error returned */
+ for (i = 0; i < 3; i++) {
/* receive 2nd answer */
ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf),
&act_len, 2000);
- if (ret)
- err("%s: recv bulk message failed: %d", __func__, ret);
- else {
+
+ if (ret) {
+ deb_info("%s: recv bulk message failed: %d",
+ __func__, ret);
+ } else {
deb_xfer("<<< ");
- debug_dump(buf, act_len, deb_xfer);
+ debug_dump(buf, rlen, deb_xfer);
+
+ if (buf[63] != 0x4f)
+ deb_info("%s: cmd failed\n", __func__);
+
+ break;
}
}
+ if (ret) {
+ /* all retries failed, it is fatal */
+ err("%s: recv bulk message failed: %d", __func__, ret);
+ goto error_unlock;
+ }
+
/* read request, copy returned data to return buf */
- if (!ret && rbuf && rlen)
+ if (rbuf && rlen)
memcpy(rbuf, buf, rlen);
+error_unlock:
mutex_unlock(&anysee_usb_mutex);
return ret;
@@ -129,6 +161,29 @@ static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
return anysee_write_reg(d, reg, val);
}
+/* read single register with mask */
+static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val,
+ u8 mask)
+{
+ int ret, i;
+ u8 tmp;
+
+ ret = anysee_read_reg(d, reg, &tmp);
+ if (ret)
+ return ret;
+
+ tmp &= mask;
+
+ /* find position of the first bit */
+ for (i = 0; i < 8; i++) {
+ if ((mask >> i) & 0x01)
+ break;
+ }
+ *val = tmp >> i;
+
+ return 0;
+}
+
static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
{
u8 buf[] = {CMD_GET_HW_INFO};
@@ -156,22 +211,6 @@ static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
}
-static int anysee_init(struct dvb_usb_device *d)
-{
- int ret;
- /* LED light */
- ret = anysee_led_ctrl(d, 0x01, 0x03);
- if (ret)
- return ret;
-
- /* enable IR */
- ret = anysee_ir_ctrl(d, 1);
- if (ret)
- return ret;
-
- return 0;
-}
-
/* I2C */
static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
int num)
@@ -297,7 +336,7 @@ static struct tda10023_config anysee_tda10023_tda18212_config = {
.pll_m = 12,
.pll_p = 3,
.pll_n = 1,
- .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
+ .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B,
.deltaf = 0xba02,
};
@@ -309,6 +348,17 @@ static struct tda18212_config anysee_tda18212_config = {
.if_dvbc = 5000,
};
+static struct tda18212_config anysee_tda18212_config2 = {
+ .i2c_address = 0x60 /* (0xc0 >> 1) */,
+ .if_dvbt_6 = 3550,
+ .if_dvbt_7 = 3700,
+ .if_dvbt_8 = 4150,
+ .if_dvbt2_6 = 3250,
+ .if_dvbt2_7 = 4000,
+ .if_dvbt2_8 = 4000,
+ .if_dvbc = 5000,
+};
+
static struct cx24116_config anysee_cx24116_config = {
.demod_address = (0xaa >> 1),
.mpg_clk_pos_pol = 0x00,
@@ -339,6 +389,11 @@ static struct isl6423_config anysee_isl6423_config = {
.addr = (0x10 >> 1),
};
+static struct cxd2820r_config anysee_cxd2820r_config = {
+ .i2c_address = 0x6d, /* (0xda >> 1) */
+ .ts_mode = 0x38,
+};
+
/*
* New USB device strings: Mfr=1, Product=2, SerialNumber=0
* Manufacturer: AMT.CO.KR
@@ -421,6 +476,14 @@ static struct isl6423_config anysee_isl6423_config = {
* IOA[7] TS 1=enabled
* IOE[5] STV0903 1=enabled
*
+ * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)"
+ * PCB: 508T2C (rev0.3)
+ * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[5] CXD2820R 1=enabled
+ *
* E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)"
* PCB: 508PTC (rev0.5)
* parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
@@ -437,7 +500,7 @@ static struct isl6423_config anysee_isl6423_config = {
* IOD[6] ZL10353 1=enabled
* IOE[0] IF 0=enabled
*
- * E7 S2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)"
+ * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)"
* PCB: 508PS2 (rev0.4)
* parts: DNBU10512IST(STV0903, STV6110), ISL6423
* OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
@@ -446,6 +509,16 @@ static struct isl6423_config anysee_isl6423_config = {
* IOE[5] STV0903 1=enabled
*/
+
+/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */
+static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+ /* enable / disable tuner access on IOE[4] */
+ return anysee_wr_reg_mask(adap->dev, REG_IOE, (enable << 4), 0x10);
+}
+
static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
@@ -577,7 +650,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
/* detect hardware only once */
if (adap->fe_adap[0].fe == NULL) {
/* Check which hardware we have.
- * We must do this call two times to get reliable values (hw bug).
+ * We must do this call two times to get reliable values
+ * (hw/fw bug).
*/
ret = anysee_get_hw_info(adap->dev, hw_info);
if (ret)
@@ -606,14 +680,14 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
break;
/* attach demod */
- adap->fe_adap[0].fe = dvb_attach(mt352_attach, &anysee_mt352_config,
- &adap->dev->i2c_adap);
+ adap->fe_adap[0].fe = dvb_attach(mt352_attach,
+ &anysee_mt352_config, &adap->dev->i2c_adap);
if (adap->fe_adap[0].fe)
break;
/* attach demod */
- adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
- &adap->dev->i2c_adap);
+ adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
+ &anysee_zl10353_config, &adap->dev->i2c_adap);
break;
case ANYSEE_HW_507CD: /* 6 */
@@ -665,8 +739,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
goto error;
/* attach demod */
- adap->fe_adap[0].fe = dvb_attach(cx24116_attach, &anysee_cx24116_config,
- &adap->dev->i2c_adap);
+ adap->fe_adap[0].fe = dvb_attach(cx24116_attach,
+ &anysee_cx24116_config, &adap->dev->i2c_adap);
break;
case ANYSEE_HW_507FA: /* 15 */
@@ -747,17 +821,19 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
}
}
+ /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+ if (tmp == 0xc7) {
+ if (adap->fe_adap[state->fe_id].fe)
+ adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl =
+ anysee_i2c_gate_ctrl;
+ }
+
break;
case ANYSEE_HW_508TC: /* 18 */
case ANYSEE_HW_508PTC: /* 21 */
/* E7 TC */
/* E7 PTC */
- /* enable transport stream on IOA[7] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
- if (ret)
- goto error;
-
if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) {
/* disable DVB-T demod on IOD[6] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
@@ -772,7 +848,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
goto error;
/* attach demod */
- adap->fe_adap[state->fe_id].fe = dvb_attach(tda10023_attach,
+ adap->fe_adap[state->fe_id].fe =
+ dvb_attach(tda10023_attach,
&anysee_tda10023_tda18212_config,
&adap->dev->i2c_adap, 0x48);
} else {
@@ -789,11 +866,19 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
goto error;
/* attach demod */
- adap->fe_adap[state->fe_id].fe = dvb_attach(zl10353_attach,
+ adap->fe_adap[state->fe_id].fe =
+ dvb_attach(zl10353_attach,
&anysee_zl10353_tda18212_config,
&adap->dev->i2c_adap);
}
+ /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+ if (adap->fe_adap[state->fe_id].fe)
+ adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl =
+ anysee_i2c_gate_ctrl;
+
+ state->has_ci = true;
+
break;
case ANYSEE_HW_508S2: /* 19 */
case ANYSEE_HW_508PS2: /* 22 */
@@ -803,19 +888,34 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
if (state->fe_id)
break;
- /* enable transport stream on IOA[7] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
+ /* enable DVB-S/S2 demod on IOE[5] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
if (ret)
goto error;
- /* enable DVB-S/S2 demod on IOE[5] */
+ /* attach demod */
+ adap->fe_adap[0].fe = dvb_attach(stv0900_attach,
+ &anysee_stv0900_config, &adap->dev->i2c_adap, 0);
+
+ state->has_ci = true;
+
+ break;
+ case ANYSEE_HW_508T2C: /* 20 */
+ /* E7 T2C */
+
+ if (state->fe_id)
+ break;
+
+ /* enable DVB-T/T2/C demod on IOE[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
if (ret)
goto error;
/* attach demod */
- adap->fe_adap[0].fe = dvb_attach(stv0900_attach, &anysee_stv0900_config,
- &adap->dev->i2c_adap, 0);
+ adap->fe_adap[state->fe_id].fe = dvb_attach(cxd2820r_attach,
+ &anysee_cxd2820r_config, &adap->dev->i2c_adap);
+
+ state->has_ci = true;
break;
}
@@ -842,24 +942,26 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
/* E30 */
/* attach tuner */
- fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1),
- NULL, DVB_PLL_THOMSON_DTT7579);
+ fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe,
+ (0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579);
break;
case ANYSEE_HW_507CD: /* 6 */
/* E30 Plus */
/* attach tuner */
- fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1),
- &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579);
+ fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe,
+ (0xc2 >> 1), &adap->dev->i2c_adap,
+ DVB_PLL_THOMSON_DTT7579);
break;
case ANYSEE_HW_507DC: /* 10 */
/* E30 C Plus */
/* attach tuner */
- fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc0 >> 1),
- &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+ fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe,
+ (0xc0 >> 1), &adap->dev->i2c_adap,
+ DVB_PLL_SAMSUNG_DTOS403IH102A);
break;
case ANYSEE_HW_507SI: /* 11 */
@@ -877,22 +979,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
/* Try first attach TDA18212 silicon tuner on IOE[4], if that
* fails attach old simple PLL. */
- /* enable tuner on IOE[4] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
- if (ret)
- goto error;
-
/* attach tuner */
fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
&adap->dev->i2c_adap, &anysee_tda18212_config);
if (fe)
break;
- /* disable tuner on IOE[4] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
- if (ret)
- goto error;
-
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe,
(0xc0 >> 1), &adap->dev->i2c_adap,
@@ -904,11 +996,6 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
/* E7 TC */
/* E7 PTC */
- /* enable tuner on IOE[4] */
- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
- if (ret)
- goto error;
-
/* attach tuner */
fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
&adap->dev->i2c_adap, &anysee_tda18212_config);
@@ -930,6 +1017,15 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
}
break;
+
+ case ANYSEE_HW_508T2C: /* 20 */
+ /* E7 T2C */
+
+ /* attach tuner */
+ fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
+ &adap->dev->i2c_adap, &anysee_tda18212_config2);
+
+ break;
default:
fe = NULL;
}
@@ -939,7 +1035,6 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
else
ret = -ENODEV;
-error:
return ret;
}
@@ -969,6 +1064,209 @@ static int anysee_rc_query(struct dvb_usb_device *d)
return 0;
}
+static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
+ int addr)
+{
+ struct dvb_usb_device *d = ci->data;
+ int ret;
+ u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1};
+ u8 val;
+
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1);
+ if (ret)
+ return ret;
+
+ return val;
+}
+
+static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
+ int addr, u8 val)
+{
+ struct dvb_usb_device *d = ci->data;
+ int ret;
+ u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val};
+
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot,
+ u8 addr)
+{
+ struct dvb_usb_device *d = ci->data;
+ int ret;
+ u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1};
+ u8 val;
+
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1);
+ if (ret)
+ return ret;
+
+ return val;
+}
+
+static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot,
+ u8 addr, u8 val)
+{
+ struct dvb_usb_device *d = ci->data;
+ int ret;
+ u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val};
+
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot)
+{
+ struct dvb_usb_device *d = ci->data;
+ int ret;
+ struct anysee_state *state = d->priv;
+
+ state->ci_cam_ready = jiffies + msecs_to_jiffies(1000);
+
+ ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
+ if (ret)
+ return ret;
+
+ msleep(300);
+
+ ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot)
+{
+ struct dvb_usb_device *d = ci->data;
+ int ret;
+
+ ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
+ if (ret)
+ return ret;
+
+ msleep(30);
+
+ ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot)
+{
+ struct dvb_usb_device *d = ci->data;
+ int ret;
+
+ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot,
+ int open)
+{
+ struct dvb_usb_device *d = ci->data;
+ struct anysee_state *state = d->priv;
+ int ret;
+ u8 tmp;
+
+ ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40);
+ if (ret)
+ return ret;
+
+ if (tmp == 0) {
+ ret = DVB_CA_EN50221_POLL_CAM_PRESENT;
+ if (time_after(jiffies, state->ci_cam_ready))
+ ret |= DVB_CA_EN50221_POLL_CAM_READY;
+ }
+
+ return ret;
+}
+
+static int anysee_ci_init(struct dvb_usb_device *d)
+{
+ struct anysee_state *state = d->priv;
+ int ret;
+
+ state->ci.owner = THIS_MODULE;
+ state->ci.read_attribute_mem = anysee_ci_read_attribute_mem;
+ state->ci.write_attribute_mem = anysee_ci_write_attribute_mem;
+ state->ci.read_cam_control = anysee_ci_read_cam_control;
+ state->ci.write_cam_control = anysee_ci_write_cam_control;
+ state->ci.slot_reset = anysee_ci_slot_reset;
+ state->ci.slot_shutdown = anysee_ci_slot_shutdown;
+ state->ci.slot_ts_enable = anysee_ci_slot_ts_enable;
+ state->ci.poll_slot_status = anysee_ci_poll_slot_status;
+ state->ci.data = d;
+
+ ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
+ if (ret)
+ return ret;
+
+ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 2)|(0 << 1)|(0 << 0), 0x07);
+ if (ret)
+ return ret;
+
+ ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 2)|(1 << 1)|(1 << 0), 0x07);
+ if (ret)
+ return ret;
+
+ ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void anysee_ci_release(struct dvb_usb_device *d)
+{
+ struct anysee_state *state = d->priv;
+
+ /* detach CI */
+ if (state->has_ci)
+ dvb_ca_en50221_release(&state->ci);
+
+ return;
+}
+
+static int anysee_init(struct dvb_usb_device *d)
+{
+ struct anysee_state *state = d->priv;
+ int ret;
+
+ /* LED light */
+ ret = anysee_led_ctrl(d, 0x01, 0x03);
+ if (ret)
+ return ret;
+
+ /* enable IR */
+ ret = anysee_ir_ctrl(d, 1);
+ if (ret)
+ return ret;
+
+ /* attach CI */
+ if (state->has_ci) {
+ ret = anysee_ci_init(d);
+ if (ret) {
+ state->has_ci = false;
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties anysee_properties;
@@ -1010,6 +1308,16 @@ static int anysee_probe(struct usb_interface *intf,
return anysee_init(d);
}
+static void anysee_disconnect(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+
+ anysee_ci_release(d);
+ dvb_usb_device_exit(intf);
+
+ return;
+}
+
static struct usb_device_id anysee_table[] = {
{ USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
{ USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) },
@@ -1029,7 +1337,7 @@ static struct dvb_usb_device_properties anysee_properties = {
{
.num_frontends = 2,
.frontend_ctrl = anysee_frontend_ctrl,
- .fe = {{
+ .fe = { {
.streaming_ctrl = anysee_streaming_ctrl,
.frontend_attach = anysee_frontend_attach,
.tuner_attach = anysee_tuner_attach,
@@ -1057,7 +1365,7 @@ static struct dvb_usb_device_properties anysee_properties = {
}
}
},
- }},
+ } },
}
},
@@ -1087,7 +1395,7 @@ static struct dvb_usb_device_properties anysee_properties = {
static struct usb_driver anysee_driver = {
.name = "dvb_usb_anysee",
.probe = anysee_probe,
- .disconnect = dvb_usb_device_exit,
+ .disconnect = anysee_disconnect,
.id_table = anysee_table,
};
diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h
index 57ee500b8c0e..8ac879431540 100644
--- a/drivers/media/dvb/dvb-usb/anysee.h
+++ b/drivers/media/dvb/dvb-usb/anysee.h
@@ -36,6 +36,7 @@
#define DVB_USB_LOG_PREFIX "anysee"
#include "dvb-usb.h"
+#include "dvb_ca_en50221.h"
#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args)
#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args)
@@ -54,12 +55,16 @@ enum cmd {
CMD_GET_IR_CODE = 0x41,
CMD_GET_HW_INFO = 0x19,
CMD_SMARTCARD = 0x34,
+ CMD_CI = 0x37,
};
struct anysee_state {
u8 hw; /* PCB ID */
u8 seq;
u8 fe_id:1; /* frondend ID */
+ u8 has_ci:1;
+ struct dvb_ca_en50221 ci;
+ unsigned long ci_cam_ready; /* jiffies */
};
#define ANYSEE_HW_507T 2 /* E30 */
@@ -69,6 +74,7 @@ struct anysee_state {
#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */
#define ANYSEE_HW_508TC 18 /* E7 TC */
#define ANYSEE_HW_508S2 19 /* E7 S2 */
+#define ANYSEE_HW_508T2C 20 /* E7 T2C */
#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */
#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */
diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c
new file mode 100644
index 000000000000..4008b9c50fbd
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/az6007.c
@@ -0,0 +1,957 @@
+/*
+ * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones
+ *
+ * Copyright (c) Henry Wang <Henry.wang@AzureWave.com>
+ *
+ * This driver was made publicly available by Terratec, at:
+ * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
+ * The original driver's license is GPL, as declared with MODULE_LICENSE()
+ *
+ * Copyright (c) 2010-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Driver modified by in order to work with upstream drxk driver, and
+ * tons of bugs got fixed.
+ *
+ * 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 under version 2 of the License.
+ *
+ * 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.
+ */
+
+#include "drxk.h"
+#include "mt2063.h"
+#include "dvb_ca_en50221.h"
+
+#define DVB_USB_LOG_PREFIX "az6007"
+#include "dvb-usb.h"
+
+/* debug */
+int dvb_usb_az6007_debug;
+module_param_named(debug, dvb_usb_az6007_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))."
+ DVB_USB_DEBUG_STATUS);
+
+#define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args)
+#define deb_rc(args...) dprintk(dvb_usb_az6007_debug, 0x04, args)
+#define deb_fe(args...) dprintk(dvb_usb_az6007_debug, 0x08, args)
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/
+
+#define FX2_OED 0xb5
+#define AZ6007_READ_DATA 0xb7
+#define AZ6007_I2C_RD 0xb9
+#define AZ6007_POWER 0xbc
+#define AZ6007_I2C_WR 0xbd
+#define FX2_SCON1 0xc0
+#define AZ6007_TS_THROUGH 0xc7
+#define AZ6007_READ_IR 0xb4
+
+struct az6007_device_state {
+ struct mutex mutex;
+ struct mutex ca_mutex;
+ struct dvb_ca_en50221 ca;
+ unsigned warm:1;
+ int (*gate_ctrl) (struct dvb_frontend *, int);
+ unsigned char data[4096];
+};
+
+static struct drxk_config terratec_h7_drxk = {
+ .adr = 0x29,
+ .parallel_ts = true,
+ .dynamic_clk = true,
+ .single_master = true,
+ .enable_merr_cfg = true,
+ .no_i2c_bridge = false,
+ .chunk_size = 64,
+ .mpeg_out_clk_strength = 0x02,
+ .microcode_name = "dvb-usb-terratec-h7-drxk.fw",
+};
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct dvb_usb_adapter *adap = fe->sec_priv;
+ struct az6007_device_state *st;
+ int status = 0;
+
+ deb_info("%s: %s\n", __func__, enable ? "enable" : "disable");
+
+ if (!adap)
+ return -EINVAL;
+
+ st = adap->dev->priv;
+
+ if (!st)
+ return -EINVAL;
+
+ if (enable)
+ status = st->gate_ctrl(fe, 1);
+ else
+ status = st->gate_ctrl(fe, 0);
+
+ return status;
+}
+
+static struct mt2063_config az6007_mt2063_config = {
+ .tuner_address = 0x60,
+ .refclock = 36125000,
+};
+
+static int __az6007_read(struct usb_device *udev, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
+{
+ int ret;
+
+ ret = usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ value, index, b, blen, 5000);
+ if (ret < 0) {
+ warn("usb read operation failed. (%d)", ret);
+ return -EIO;
+ }
+
+ deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
+ index);
+ debug_dump(b, blen, deb_xfer);
+
+ return ret;
+}
+
+static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
+{
+ struct az6007_device_state *st = d->priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&st->mutex) < 0)
+ return -EAGAIN;
+
+ ret = __az6007_read(d->udev, req, value, index, b, blen);
+
+ mutex_unlock(&st->mutex);
+
+ return ret;
+}
+
+static int __az6007_write(struct usb_device *udev, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
+{
+ int ret;
+
+ deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
+ index);
+ debug_dump(b, blen, deb_xfer);
+
+ if (blen > 64) {
+ err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n",
+ blen);
+ return -EOPNOTSUPP;
+ }
+
+ ret = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ value, index, b, blen, 5000);
+ if (ret != blen) {
+ err("usb write operation failed. (%d)", ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
+{
+ struct az6007_device_state *st = d->priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&st->mutex) < 0)
+ return -EAGAIN;
+
+ ret = __az6007_write(d->udev, req, value, index, b, blen);
+
+ mutex_unlock(&st->mutex);
+
+ return ret;
+}
+
+static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct dvb_usb_device *d = adap->dev;
+
+ deb_info("%s: %s", __func__, onoff ? "enable" : "disable");
+
+ return az6007_write(d, 0xbc, onoff, 0, NULL, 0);
+}
+
+/* remote control stuff (does not work with my box) */
+static int az6007_rc_query(struct dvb_usb_device *d)
+{
+ struct az6007_device_state *st = d->priv;
+ unsigned code = 0;
+
+ az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
+
+ if (st->data[1] == 0x44)
+ return 0;
+
+ if ((st->data[1] ^ st->data[2]) == 0xff)
+ code = st->data[1];
+ else
+ code = st->data[1] << 8 | st->data[2];
+
+ if ((st->data[3] ^ st->data[4]) == 0xff)
+ code = code << 8 | st->data[3];
+ else
+ code = code << 16 | st->data[3] << 8 | st->data[4];
+
+ rc_keydown(d->rc_dev, code, st->data[5]);
+
+ return 0;
+}
+
+static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+ int slot,
+ int address)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+ u8 *b;
+
+ if (slot != 0)
+ return -EINVAL;
+
+ b = kmalloc(12, GFP_KERNEL);
+ if (!b)
+ return -ENOMEM;
+
+ mutex_lock(&state->ca_mutex);
+
+ req = 0xC1;
+ value = address;
+ index = 0;
+ blen = 1;
+
+ ret = az6007_read(d, req, value, index, b, blen);
+ if (ret < 0) {
+ warn("usb in operation failed. (%d)", ret);
+ ret = -EINVAL;
+ } else {
+ ret = b[0];
+ }
+
+ mutex_unlock(&state->ca_mutex);
+ kfree(b);
+ return ret;
+}
+
+static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+ int slot,
+ int address,
+ u8 value)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+ int ret;
+ u8 req;
+ u16 value1;
+ u16 index;
+ int blen;
+
+ deb_info("%s %d", __func__, slot);
+ if (slot != 0)
+ return -EINVAL;
+
+ mutex_lock(&state->ca_mutex);
+ req = 0xC2;
+ value1 = address;
+ index = value;
+ blen = 0;
+
+ ret = az6007_write(d, req, value1, index, NULL, blen);
+ if (ret != 0)
+ warn("usb out operation failed. (%d)", ret);
+
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+ int slot,
+ u8 address)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+ u8 *b;
+
+ if (slot != 0)
+ return -EINVAL;
+
+ b = kmalloc(12, GFP_KERNEL);
+ if (!b)
+ return -ENOMEM;
+
+ mutex_lock(&state->ca_mutex);
+
+ req = 0xC3;
+ value = address;
+ index = 0;
+ blen = 2;
+
+ ret = az6007_read(d, req, value, index, b, blen);
+ if (ret < 0) {
+ warn("usb in operation failed. (%d)", ret);
+ ret = -EINVAL;
+ } else {
+ if (b[0] == 0)
+ warn("Read CI IO error");
+
+ ret = b[1];
+ deb_info("read cam data = %x from 0x%x", b[1], value);
+ }
+
+ mutex_unlock(&state->ca_mutex);
+ kfree(b);
+ return ret;
+}
+
+static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+ int slot,
+ u8 address,
+ u8 value)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+ int ret;
+ u8 req;
+ u16 value1;
+ u16 index;
+ int blen;
+
+ if (slot != 0)
+ return -EINVAL;
+
+ mutex_lock(&state->ca_mutex);
+ req = 0xC4;
+ value1 = address;
+ index = value;
+ blen = 0;
+
+ ret = az6007_write(d, req, value1, index, NULL, blen);
+ if (ret != 0) {
+ warn("usb out operation failed. (%d)", ret);
+ goto failed;
+ }
+
+failed:
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+ u8 *b;
+
+ b = kmalloc(12, GFP_KERNEL);
+ if (!b)
+ return -ENOMEM;
+
+ req = 0xC8;
+ value = 0;
+ index = 0;
+ blen = 1;
+
+ ret = az6007_read(d, req, value, index, b, blen);
+ if (ret < 0) {
+ warn("usb in operation failed. (%d)", ret);
+ ret = -EIO;
+ } else{
+ ret = b[0];
+ }
+ kfree(b);
+ return ret;
+}
+
+static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+ int ret, i;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+
+ mutex_lock(&state->ca_mutex);
+
+ req = 0xC6;
+ value = 1;
+ index = 0;
+ blen = 0;
+
+ ret = az6007_write(d, req, value, index, NULL, blen);
+ if (ret != 0) {
+ warn("usb out operation failed. (%d)", ret);
+ goto failed;
+ }
+
+ msleep(500);
+ req = 0xC6;
+ value = 0;
+ index = 0;
+ blen = 0;
+
+ ret = az6007_write(d, req, value, index, NULL, blen);
+ if (ret != 0) {
+ warn("usb out operation failed. (%d)", ret);
+ goto failed;
+ }
+
+ for (i = 0; i < 15; i++) {
+ msleep(100);
+
+ if (CI_CamReady(ca, slot)) {
+ deb_info("CAM Ready");
+ break;
+ }
+ }
+ msleep(5000);
+
+failed:
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+ return 0;
+}
+
+static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+
+ deb_info("%s", __func__);
+ mutex_lock(&state->ca_mutex);
+ req = 0xC7;
+ value = 1;
+ index = 0;
+ blen = 0;
+
+ ret = az6007_write(d, req, value, index, NULL, blen);
+ if (ret != 0) {
+ warn("usb out operation failed. (%d)", ret);
+ goto failed;
+ }
+
+failed:
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+ u8 *b;
+
+ b = kmalloc(12, GFP_KERNEL);
+ if (!b)
+ return -ENOMEM;
+ mutex_lock(&state->ca_mutex);
+
+ req = 0xC5;
+ value = 0;
+ index = 0;
+ blen = 1;
+
+ ret = az6007_read(d, req, value, index, b, blen);
+ if (ret < 0) {
+ warn("usb in operation failed. (%d)", ret);
+ ret = -EIO;
+ } else
+ ret = 0;
+
+ if (!ret && b[0] == 1) {
+ ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
+ DVB_CA_EN50221_POLL_CAM_READY;
+ }
+
+ mutex_unlock(&state->ca_mutex);
+ kfree(b);
+ return ret;
+}
+
+
+static void az6007_ci_uninit(struct dvb_usb_device *d)
+{
+ struct az6007_device_state *state;
+
+ deb_info("%s", __func__);
+
+ if (NULL == d)
+ return;
+
+ state = (struct az6007_device_state *)d->priv;
+ if (NULL == state)
+ return;
+
+ if (NULL == state->ca.data)
+ return;
+
+ dvb_ca_en50221_release(&state->ca);
+
+ memset(&state->ca, 0, sizeof(state->ca));
+}
+
+
+static int az6007_ci_init(struct dvb_usb_adapter *a)
+{
+ struct dvb_usb_device *d = a->dev;
+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+ int ret;
+
+ deb_info("%s", __func__);
+
+ mutex_init(&state->ca_mutex);
+
+ state->ca.owner = THIS_MODULE;
+ state->ca.read_attribute_mem = az6007_ci_read_attribute_mem;
+ state->ca.write_attribute_mem = az6007_ci_write_attribute_mem;
+ state->ca.read_cam_control = az6007_ci_read_cam_control;
+ state->ca.write_cam_control = az6007_ci_write_cam_control;
+ state->ca.slot_reset = az6007_ci_slot_reset;
+ state->ca.slot_shutdown = az6007_ci_slot_shutdown;
+ state->ca.slot_ts_enable = az6007_ci_slot_ts_enable;
+ state->ca.poll_slot_status = az6007_ci_poll_slot_status;
+ state->ca.data = d;
+
+ ret = dvb_ca_en50221_init(&a->dvb_adap,
+ &state->ca,
+ 0, /* flags */
+ 1);/* n_slots */
+ if (ret != 0) {
+ err("Cannot initialize CI: Error %d.", ret);
+ memset(&state->ca, 0, sizeof(state->ca));
+ return ret;
+ }
+
+ deb_info("CI initialized.");
+
+ return 0;
+}
+
+static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
+{
+ struct az6007_device_state *st = d->priv;
+ int ret;
+
+ ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6);
+ memcpy(mac, st->data, sizeof(mac));
+
+ if (ret > 0)
+ deb_info("%s: mac is %02x:%02x:%02x:%02x:%02x:%02x\n",
+ __func__, mac[0], mac[1], mac[2],
+ mac[3], mac[4], mac[5]);
+
+ return ret;
+}
+
+static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct az6007_device_state *st = adap->dev->priv;
+
+ deb_info("attaching demod drxk");
+
+ adap->fe_adap[0].fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
+ &adap->dev->i2c_adap);
+ if (!adap->fe_adap[0].fe)
+ return -EINVAL;
+
+ adap->fe_adap[0].fe->sec_priv = adap;
+ st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl;
+ adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+ az6007_ci_init(adap);
+
+ return 0;
+}
+
+static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ deb_info("attaching tuner mt2063");
+
+ /* Attach mt2063 to DVB-C frontend */
+ if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
+ adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
+ if (!dvb_attach(mt2063_attach, adap->fe_adap[0].fe,
+ &az6007_mt2063_config,
+ &adap->dev->i2c_adap))
+ return -EINVAL;
+
+ if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
+ adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
+
+ return 0;
+}
+
+int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ struct az6007_device_state *st = d->priv;
+ int ret;
+
+ deb_info("%s()\n", __func__);
+
+ if (!st->warm) {
+ mutex_init(&st->mutex);
+
+ ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0);
+ if (ret < 0)
+ return ret;
+ msleep(60);
+ ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
+ if (ret < 0)
+ return ret;
+ msleep(100);
+ ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0);
+ if (ret < 0)
+ return ret;
+ msleep(20);
+ ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ msleep(400);
+ ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0);
+ if (ret < 0)
+ return ret;
+ msleep(150);
+ ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0);
+ if (ret < 0)
+ return ret;
+ msleep(430);
+ ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ st->warm = true;
+
+ return 0;
+ }
+
+ if (!onoff)
+ return 0;
+
+ az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
+ az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0);
+
+ return 0;
+}
+
+/* I2C */
+static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct az6007_device_state *st = d->priv;
+ int i, j, len;
+ int ret = 0;
+ u16 index;
+ u16 value;
+ int length;
+ u8 req, addr;
+
+ if (mutex_lock_interruptible(&st->mutex) < 0)
+ return -EAGAIN;
+
+ for (i = 0; i < num; i++) {
+ addr = msgs[i].addr << 1;
+ if (((i + 1) < num)
+ && (msgs[i].len == 1)
+ && (!msgs[i].flags & I2C_M_RD)
+ && (msgs[i + 1].flags & I2C_M_RD)
+ && (msgs[i].addr == msgs[i + 1].addr)) {
+ /*
+ * A write + read xfer for the same address, where
+ * the first xfer has just 1 byte length.
+ * Need to join both into one operation
+ */
+ if (dvb_usb_az6007_debug & 2)
+ printk(KERN_DEBUG
+ "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ",
+ addr, msgs[i].len, msgs[i + 1].len);
+ req = AZ6007_I2C_RD;
+ index = msgs[i].buf[0];
+ value = addr | (1 << 8);
+ length = 6 + msgs[i + 1].len;
+ len = msgs[i + 1].len;
+ ret = __az6007_read(d->udev, req, value, index,
+ st->data, length);
+ if (ret >= len) {
+ for (j = 0; j < len; j++) {
+ msgs[i + 1].buf[j] = st->data[j + 5];
+ if (dvb_usb_az6007_debug & 2)
+ printk(KERN_CONT
+ "0x%02x ",
+ msgs[i + 1].buf[j]);
+ }
+ } else
+ ret = -EIO;
+ i++;
+ } else if (!(msgs[i].flags & I2C_M_RD)) {
+ /* write bytes */
+ if (dvb_usb_az6007_debug & 2)
+ printk(KERN_DEBUG
+ "az6007 I2C xfer write addr=0x%x len=%d: ",
+ addr, msgs[i].len);
+ req = AZ6007_I2C_WR;
+ index = msgs[i].buf[0];
+ value = addr | (1 << 8);
+ length = msgs[i].len - 1;
+ len = msgs[i].len - 1;
+ if (dvb_usb_az6007_debug & 2)
+ printk(KERN_CONT "(0x%02x) ", msgs[i].buf[0]);
+ for (j = 0; j < len; j++) {
+ st->data[j] = msgs[i].buf[j + 1];
+ if (dvb_usb_az6007_debug & 2)
+ printk(KERN_CONT "0x%02x ",
+ st->data[j]);
+ }
+ ret = __az6007_write(d->udev, req, value, index,
+ st->data, length);
+ } else {
+ /* read bytes */
+ if (dvb_usb_az6007_debug & 2)
+ printk(KERN_DEBUG
+ "az6007 I2C xfer read addr=0x%x len=%d: ",
+ addr, msgs[i].len);
+ req = AZ6007_I2C_RD;
+ index = msgs[i].buf[0];
+ value = addr;
+ length = msgs[i].len + 6;
+ len = msgs[i].len;
+ ret = __az6007_read(d->udev, req, value, index,
+ st->data, length);
+ for (j = 0; j < len; j++) {
+ msgs[i].buf[j] = st->data[j + 5];
+ if (dvb_usb_az6007_debug & 2)
+ printk(KERN_CONT
+ "0x%02x ", st->data[j + 5]);
+ }
+ }
+ if (dvb_usb_az6007_debug & 2)
+ printk(KERN_CONT "\n");
+ if (ret < 0)
+ goto err;
+ }
+err:
+ mutex_unlock(&st->mutex);
+
+ if (ret < 0) {
+ info("%s ERROR: %i", __func__, ret);
+ return ret;
+ }
+ return num;
+}
+
+static u32 az6007_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm az6007_i2c_algo = {
+ .master_xfer = az6007_i2c_xfer,
+ .functionality = az6007_i2c_func,
+};
+
+int az6007_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc, int *cold)
+{
+ int ret;
+ u8 *mac;
+
+ mac = kmalloc(6, GFP_ATOMIC);
+ if (!mac)
+ return -ENOMEM;
+
+ /* Try to read the mac address */
+ ret = __az6007_read(udev, AZ6007_READ_DATA, 6, 0, mac, 6);
+ if (ret == 6)
+ *cold = 0;
+ else
+ *cold = 1;
+
+ kfree(mac);
+
+ if (*cold) {
+ __az6007_write(udev, 0x09, 1, 0, NULL, 0);
+ __az6007_write(udev, 0x00, 0, 0, NULL, 0);
+ __az6007_write(udev, 0x00, 0, 0, NULL, 0);
+ }
+
+ deb_info("Device is on %s state\n", *cold ? "warm" : "cold");
+ return 0;
+}
+
+static struct dvb_usb_device_properties az6007_properties;
+
+static void az6007_usb_disconnect(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ az6007_ci_uninit(d);
+ dvb_usb_device_exit(intf);
+}
+
+static int az6007_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf, &az6007_properties,
+ THIS_MODULE, NULL, adapter_nr);
+}
+
+static struct usb_device_id az6007_usb_table[] = {
+ {USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007)},
+ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7)},
+ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2)},
+ {0},
+};
+
+MODULE_DEVICE_TABLE(usb, az6007_usb_table);
+
+static struct dvb_usb_device_properties az6007_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-terratec-h7-az6007.fw",
+ .no_reconnect = 1,
+ .size_of_priv = sizeof(struct az6007_device_state),
+ .identify_state = az6007_identify_state,
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {{
+ .streaming_ctrl = az6007_streaming_ctrl,
+ .tuner_attach = az6007_tuner_attach,
+ .frontend_attach = az6007_frontend_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 10,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+ } }
+ } },
+ .power_ctrl = az6007_power_ctrl,
+ .read_mac_address = az6007_read_mac_addr,
+
+ .rc.core = {
+ .rc_interval = 400,
+ .rc_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+ .module_name = "az6007",
+ .rc_query = az6007_rc_query,
+ .allowed_protos = RC_TYPE_NEC,
+ },
+ .i2c_algo = &az6007_i2c_algo,
+
+ .num_device_descs = 2,
+ .devices = {
+ { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)",
+ .cold_ids = { &az6007_usb_table[0], NULL },
+ .warm_ids = { NULL },
+ },
+ { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)",
+ .cold_ids = { &az6007_usb_table[1], &az6007_usb_table[2], NULL },
+ .warm_ids = { NULL },
+ },
+ { NULL },
+ }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver az6007_usb_driver = {
+ .name = "dvb_usb_az6007",
+ .probe = az6007_usb_probe,
+ .disconnect = az6007_usb_disconnect,
+ .id_table = az6007_usb_table,
+};
+
+/* module stuff */
+static int __init az6007_usb_module_init(void)
+{
+ int result;
+ deb_info("az6007 usb module init\n");
+
+ result = usb_register(&az6007_usb_driver);
+ if (result) {
+ err("usb_register failed. (%d)", result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit az6007_usb_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ deb_info("az6007 usb module exit\n");
+ usb_deregister(&az6007_usb_driver);
+}
+
+module_init(az6007_usb_module_init);
+module_exit(az6007_usb_module_exit);
+
+MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
+MODULE_VERSION("1.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c
index 9cd51ac12076..1efc028a76c9 100644
--- a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c
+++ b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c
@@ -40,9 +40,8 @@
* We replace errornous fields by default TPS fields (the ones with value 0).
*/
-static uint16_t compute_tps(struct dvb_frontend_parameters *p)
+static uint16_t compute_tps(struct dtv_frontend_properties *op)
{
- struct dvb_ofdm_parameters *op = &p->u.ofdm;
uint16_t tps = 0;
switch (op->code_rate_HP) {
@@ -83,7 +82,7 @@ static uint16_t compute_tps(struct dvb_frontend_parameters *p)
/* tps |= (0 << 4) */;
}
- switch (op->constellation) {
+ switch (op->modulation) {
case QAM_16:
tps |= (1 << 13);
break;
@@ -119,7 +118,7 @@ static uint16_t compute_tps(struct dvb_frontend_parameters *p)
/* tps |= (0 << 2) */;
}
- switch (op->hierarchy_information) {
+ switch (op->hierarchy) {
case HIERARCHY_1:
tps |= (1 << 10);
break;
@@ -263,9 +262,9 @@ static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
return 0;
}
-static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct cinergyt2_fe_state *state = fe->demodulator_priv;
struct dvbt_set_parameters_msg param;
char result[2];
@@ -274,9 +273,21 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
param.tps = cpu_to_le16(compute_tps(fep));
param.freq = cpu_to_le32(fep->frequency / 1000);
- param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
param.flags = 0;
+ switch (fep->bandwidth_hz) {
+ default:
+ case 8000000:
+ param.bandwidth = 8;
+ break;
+ case 7000000:
+ param.bandwidth = 7;
+ break;
+ case 6000000:
+ param.bandwidth = 6;
+ break;
+ }
+
err = dvb_usb_generic_rw(state->d,
(char *)&param, sizeof(param),
result, sizeof(result), 0);
@@ -286,12 +297,6 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
return (err < 0) ? err : 0;
}
-static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
-{
- return 0;
-}
-
static void cinergyt2_fe_release(struct dvb_frontend *fe)
{
struct cinergyt2_fe_state *state = fe->demodulator_priv;
@@ -316,9 +321,9 @@ struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
static struct dvb_frontend_ops cinergyt2_fe_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = DRIVER_NAME,
- .type = FE_OFDM,
.frequency_min = 174000000,
.frequency_max = 862000000,
.frequency_stepsize = 166667,
@@ -341,7 +346,6 @@ static struct dvb_frontend_ops cinergyt2_fe_ops = {
.sleep = cinergyt2_fe_sleep,
.set_frontend = cinergyt2_fe_set_frontend,
- .get_frontend = cinergyt2_fe_get_frontend,
.get_tune_settings = cinergyt2_fe_get_tune_settings,
.read_status = cinergyt2_fe_read_status,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 949ea1bc0aae..3940bb0f9ef6 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -1067,18 +1067,17 @@ static struct dib0070_config dib7070p_dib0070_config = {
};
struct dib0700_adapter_state {
- int (*set_param_save) (struct dvb_frontend *,
- struct dvb_frontend_parameters *);
+ int (*set_param_save) (struct dvb_frontend *);
};
-static int dib7070_set_param_override(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int dib7070_set_param_override(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
u16 offset;
- u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+ u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
switch (band) {
case BAND_VHF: offset = 950; break;
default:
@@ -1087,7 +1086,7 @@ static int dib7070_set_param_override(struct dvb_frontend *fe,
dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
- return state->set_param_save(fe, fep);
+ return state->set_param_save(fe);
}
static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index 9bd6d51b3b93..7de125c0b36f 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -48,6 +48,8 @@ struct dib0700_state {
u8 disable_streaming_master_mode;
u32 fw_version;
u32 nb_packet_buffer_size;
+ int (*read_status)(struct dvb_frontend *, fe_status_t *);
+ int (*sleep)(struct dvb_frontend* fe);
u8 buf[255];
};
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 206999476f02..02290c60f72f 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -677,11 +677,9 @@ static void dib0700_rc_urb_completion(struct urb *purb)
u8 toggle;
deb_info("%s()\n", __func__);
- if (d == NULL)
- return;
-
if (d->rc_dev == NULL) {
/* This will occur if disable_rc_polling=1 */
+ kfree(purb->transfer_buffer);
usb_free_urb(purb);
return;
}
@@ -690,6 +688,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
if (purb->status < 0) {
deb_info("discontinuing polling\n");
+ kfree(purb->transfer_buffer);
usb_free_urb(purb);
return;
}
@@ -784,8 +783,11 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
dib0700_rc_urb_completion, d);
ret = usb_submit_urb(purb, GFP_ATOMIC);
- if (ret)
+ if (ret) {
err("rc submit urb failed\n");
+ kfree(purb->transfer_buffer);
+ usb_free_urb(purb);
+ }
return ret;
}
@@ -834,6 +836,7 @@ static struct usb_driver dib0700_driver = {
module_usb_driver(dib0700_driver);
+MODULE_FIRMWARE("dvb-usb-dib0700-1.20.fw");
MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge");
MODULE_VERSION("1.0");
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index f313182eb9d5..f9e966aa26e7 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -30,7 +30,7 @@ MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplif
"if applicable for the device (default: 0=automatic/off).");
struct dib0700_adapter_state {
- int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *);
+ int (*set_param_save) (struct dvb_frontend *);
const struct firmware *frontend_firmware;
};
@@ -804,13 +804,14 @@ static struct dib0070_config dib7770p_dib0070_config = {
.charge_pump = 2,
};
-static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib7070_set_param_override(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
u16 offset;
- u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+ u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
switch (band) {
case BAND_VHF: offset = 950; break;
case BAND_UHF:
@@ -818,17 +819,17 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_fronte
}
deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
- return state->set_param_save(fe, fep);
+ return state->set_param_save(fe);
}
-static int dib7770_set_param_override(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int dib7770_set_param_override(struct dvb_frontend *fe)
{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- struct dib0700_adapter_state *state = adap->priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
u16 offset;
- u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+ u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
switch (band) {
case BAND_VHF:
dib7000p_set_gpio(fe, 0, 0, 1);
@@ -842,7 +843,7 @@ static int dib7770_set_param_override(struct dvb_frontend *fe,
}
deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
- return state->set_param_save(fe, fep);
+ return state->set_param_save(fe);
}
static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap)
@@ -1205,14 +1206,14 @@ static struct dib0070_config dib807x_dib0070_config[2] = {
}
};
-static int dib807x_set_param_override(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int dib807x_set_param_override(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
u16 offset = dib0070_wbd_offset(fe);
- u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+ u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
switch (band) {
case BAND_VHF:
offset += 750;
@@ -1224,7 +1225,7 @@ static int dib807x_set_param_override(struct dvb_frontend *fe,
deb_info("WBD for DiB8000: %d\n", offset);
dib8000_set_wbd_ref(fe, offset);
- return state->set_param_save(fe, fep);
+ return state->set_param_save(fe);
}
static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
@@ -1279,7 +1280,7 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
- 0x80);
+ 0x80, 0);
adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
&dib807x_dib8000_config[0]);
@@ -1308,7 +1309,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
/* initialize IC 0 */
- dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80);
+ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0);
adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
&dib807x_dib8000_config[0]);
@@ -1319,7 +1320,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
{
/* initialize IC 1 */
- dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82);
+ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0);
adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82,
&dib807x_dib8000_config[1]);
@@ -1328,7 +1329,7 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
}
/* STK8096GP */
-struct dibx000_agc_config dib8090_agc_config[2] = {
+static struct dibx000_agc_config dib8090_agc_config[2] = {
{
BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
@@ -1503,22 +1504,22 @@ static struct dib0090_config dib809x_dib0090_config = {
.fref_clock_ratio = 6,
};
-static int dib8096_set_param_override(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int dib8096_set_param_override(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
- u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+ u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
u16 target;
int ret = 0;
enum frontend_tune_state tune_state = CT_SHUTDOWN;
u16 ltgain, rf_gain_limit;
- ret = state->set_param_save(fe, fep);
+ ret = state->set_param_save(fe);
if (ret < 0)
return ret;
- target = (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2;
+ target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
dib8000_set_wbd_ref(fe, target);
@@ -1578,7 +1579,7 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
msleep(10);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80);
+ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0);
adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
@@ -1629,7 +1630,7 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
msleep(20);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80);
+ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0);
adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
if (adap->fe_adap[0].fe == NULL)
@@ -1641,6 +1642,261 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
return fe_slave == NULL ? -ENODEV : 0;
}
+/* TFE8096P */
+static struct dibx000_agc_config dib8096p_agc_config[2] = {
+ {
+ .band_caps = BAND_UHF,
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
+ P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
+ P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+ P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
+ P_agc_write=0 */
+ .setup = (0 << 15) | (0 << 14) | (5 << 11)
+ | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5)
+ | (0 << 4) | (5 << 1) | (0 << 0),
+
+ .inv_gain = 684,
+ .time_stabiliz = 10,
+
+ .alpha_level = 0,
+ .thlock = 118,
+
+ .wbd_inv = 0,
+ .wbd_ref = 1200,
+ .wbd_sel = 3,
+ .wbd_alpha = 5,
+
+ .agc1_max = 65535,
+ .agc1_min = 0,
+
+ .agc2_max = 32767,
+ .agc2_min = 0,
+
+ .agc1_pt1 = 0,
+ .agc1_pt2 = 0,
+ .agc1_pt3 = 105,
+ .agc1_slope1 = 0,
+ .agc1_slope2 = 156,
+ .agc2_pt1 = 105,
+ .agc2_pt2 = 255,
+ .agc2_slope1 = 54,
+ .agc2_slope2 = 0,
+
+ .alpha_mant = 28,
+ .alpha_exp = 26,
+ .beta_mant = 31,
+ .beta_exp = 51,
+
+ .perform_agc_softsplit = 0,
+ } , {
+ .band_caps = BAND_FM | BAND_VHF | BAND_CBAND,
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
+ P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
+ P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+ P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
+ P_agc_write=0 */
+ .setup = (0 << 15) | (0 << 14) | (5 << 11)
+ | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5)
+ | (0 << 4) | (5 << 1) | (0 << 0),
+
+ .inv_gain = 732,
+ .time_stabiliz = 10,
+
+ .alpha_level = 0,
+ .thlock = 118,
+
+ .wbd_inv = 0,
+ .wbd_ref = 1200,
+ .wbd_sel = 3,
+ .wbd_alpha = 5,
+
+ .agc1_max = 65535,
+ .agc1_min = 0,
+
+ .agc2_max = 32767,
+ .agc2_min = 0,
+
+ .agc1_pt1 = 0,
+ .agc1_pt2 = 0,
+ .agc1_pt3 = 98,
+ .agc1_slope1 = 0,
+ .agc1_slope2 = 167,
+ .agc2_pt1 = 98,
+ .agc2_pt2 = 255,
+ .agc2_slope1 = 52,
+ .agc2_slope2 = 0,
+
+ .alpha_mant = 28,
+ .alpha_exp = 26,
+ .beta_mant = 31,
+ .beta_exp = 51,
+
+ .perform_agc_softsplit = 0,
+ }
+};
+
+static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = {
+ 108000, 13500,
+ 1, 9, 1, 0, 0,
+ 0, 0, 0, 0, 2,
+ (3 << 14) | (1 << 12) | (524 << 0),
+ (0 << 25) | 0,
+ 20199729,
+ 12000000,
+};
+
+static struct dib8000_config tfe8096p_dib8000_config = {
+ .output_mpeg2_in_188_bytes = 1,
+ .hostbus_diversity = 1,
+ .update_lna = NULL,
+
+ .agc_config_count = 2,
+ .agc = dib8096p_agc_config,
+ .pll = &dib8096p_clock_config_12_mhz,
+
+ .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+ .agc_control = NULL,
+ .diversity_delay = 48,
+ .output_mode = OUTMODE_MPEG2_FIFO,
+ .enMpegOutput = 1,
+};
+
+static struct dib0090_wbd_slope dib8096p_wbd_table[] = {
+ { 380, 81, 850, 64, 540, 4},
+ { 860, 51, 866, 21, 375, 4},
+ {1700, 0, 250, 0, 100, 6},
+ {2600, 0, 250, 0, 100, 6},
+ { 0xFFFF, 0, 0, 0, 0, 0},
+};
+
+static const struct dib0090_config tfe8096p_dib0090_config = {
+ .io.clock_khz = 12000,
+ .io.pll_bypass = 0,
+ .io.pll_range = 0,
+ .io.pll_prediv = 3,
+ .io.pll_loopdiv = 6,
+ .io.adc_clock_ratio = 0,
+ .io.pll_int_loop_filt = 0,
+ .reset = dib8096p_tuner_sleep,
+ .sleep = dib8096p_tuner_sleep,
+
+ .freq_offset_khz_uhf = -143,
+ .freq_offset_khz_vhf = -143,
+
+ .get_adc_power = dib8090_get_adc_power,
+
+ .clkouttobamse = 1,
+ .analog_output = 0,
+
+ .wbd_vhf_offset = 0,
+ .wbd_cband_offset = 0,
+ .use_pwm_agc = 1,
+ .clkoutdrive = 0,
+
+ .fref_clock_ratio = 1,
+
+ .wbd = dib8096p_wbd_table,
+
+ .ls_cfg_pad_drv = 0,
+ .data_tx_drv = 0,
+ .low_if = NULL,
+ .in_soc = 1,
+ .force_cband_input = 0,
+};
+
+struct dibx090p_adc {
+ u32 freq; /* RF freq MHz */
+ u32 timf; /* New Timf */
+ u32 pll_loopdiv; /* New prediv */
+ u32 pll_prediv; /* New loopdiv */
+};
+
+struct dibx090p_adc dib8090p_adc_tab[] = {
+ { 50000, 17043521, 16, 3}, /* 64 MHz */
+ {878000, 20199729, 9, 1}, /* 60 MHz */
+ {0xffffffff, 0, 0, 0}, /* 60 MHz */
+};
+
+static int dib8096p_agc_startup(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+ struct dibx000_bandwidth_config pll;
+ u16 target;
+ int better_sampling_freq = 0, ret;
+ struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0];
+
+ ret = state->set_param_save(fe);
+ if (ret < 0)
+ return ret;
+ memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
+
+ dib0090_pwm_gain_reset(fe);
+ /* dib0090_get_wbd_target is returning any possible
+ temperature compensated wbd-target */
+ target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
+ dib8000_set_wbd_ref(fe, target);
+
+
+ while (p->frequency / 1000 > adc_table->freq) {
+ better_sampling_freq = 1;
+ adc_table++;
+ }
+
+ if ((adc_table->freq != 0xffffffff) && better_sampling_freq) {
+ pll.pll_ratio = adc_table->pll_loopdiv;
+ pll.pll_prediv = adc_table->pll_prediv;
+ dib8000_update_pll(fe, &pll);
+ dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf);
+ }
+ return 0;
+}
+
+static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(20);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+
+ msleep(20);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(20);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1);
+
+ adap->fe_adap[0].fe = dvb_attach(dib8000_attach,
+ &adap->dev->i2c_adap, 0x80, &tfe8096p_dib8000_config);
+
+ return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dib0700_adapter_state *st = adap->priv;
+ struct i2c_adapter *tun_i2c = dib8096p_get_i2c_tuner(adap->fe_adap[0].fe);
+
+ if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
+ &tfe8096p_dib0090_config) == NULL)
+ return -ENODEV;
+
+ dib8000_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+ st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+ adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup;
+ return 0;
+}
+
/* STK9090M */
static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
{
@@ -1883,7 +2139,7 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap)
i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0)
return -ENODEV;
- dib0700_set_i2c_speed(adap->dev, 2000);
+ dib0700_set_i2c_speed(adap->dev, 1500);
if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0)
return -ENODEV;
release_firmware(state->frontend_firmware);
@@ -1962,7 +2218,8 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0)
return -ENODEV;
- dib0700_set_i2c_speed(adap->dev, 2000);
+
+ dib0700_set_i2c_speed(adap->dev, 1500);
if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0)
return -ENODEV;
@@ -1975,7 +2232,7 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL)
return -ENODEV;
fe_slave->dvb = adap->fe_adap[0].fe->dvb;
- dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 2000);
+ dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 1500);
if (dib9000_firmware_post_pll_init(fe_slave) < 0)
return -ENODEV;
}
@@ -2064,7 +2321,7 @@ static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_
return 0;
}
-static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib7090_agc_startup(struct dvb_frontend *fe)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
@@ -2073,13 +2330,13 @@ static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_para
struct dib7090p_best_adc adc;
int ret;
- ret = state->set_param_save(fe, fep);
+ ret = state->set_param_save(fe);
if (ret < 0)
return ret;
memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
dib0090_pwm_gain_reset(fe);
- target = (dib0090_get_wbd_offset(fe) * 8 + 1) / 2;
+ target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
dib7000p_set_wbd_ref(fe, target);
if (dib7090p_get_best_sampling(fe, &adc) == 0) {
@@ -2092,6 +2349,49 @@ static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_para
return 0;
}
+static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
+{
+ deb_info("AGC restart callback: %d", restart);
+ if (restart == 0) /* before AGC startup */
+ dib0090_set_dc_servo(fe, 1);
+ return 0;
+}
+
+static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global)
+{
+ u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1;
+ s16 wbd_delta;
+
+ if ((fe->dtv_property_cache.frequency) < 400000000)
+ threshold_agc1 = 25000;
+ else
+ threshold_agc1 = 30000;
+
+ wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2;
+ wbd_offset = dib0090_get_wbd_offset(fe);
+ dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd);
+ wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ;
+
+ deb_info("update lna, agc_global=%d agc1=%d agc2=%d",
+ agc_global, agc1, agc2);
+ deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d",
+ wbd, wbd_target, wbd_offset, wbd_delta);
+
+ if ((agc1 < threshold_agc1) && (wbd_delta > 0)) {
+ dib0090_set_switch(fe, 1, 1, 1);
+ dib0090_set_vga(fe, 0);
+ dib0090_update_rframp_7090(fe, 0);
+ dib0090_update_tuning_table_7090(fe, 0);
+ } else {
+ dib0090_set_vga(fe, 1);
+ dib0090_update_rframp_7090(fe, 1);
+ dib0090_update_tuning_table_7090(fe, 1);
+ dib0090_set_switch(fe, 0, 0, 0);
+ }
+
+ return 0;
+}
+
static struct dib0090_wbd_slope dib7090_wbd_table[] = {
{ 380, 81, 850, 64, 540, 4},
{ 860, 51, 866, 21, 375, 4},
@@ -2100,7 +2400,16 @@ static struct dib0090_wbd_slope dib7090_wbd_table[] = {
{ 0xFFFF, 0, 0, 0, 0, 0},
};
-struct dibx000_agc_config dib7090_agc_config[2] = {
+static struct dib0090_wbd_slope dib7090e_wbd_table[] = {
+ { 380, 81, 850, 64, 540, 4},
+ { 700, 51, 866, 21, 320, 4},
+ { 860, 48, 666, 18, 330, 6},
+ {1700, 0, 250, 0, 100, 6},
+ {2600, 0, 250, 0, 100, 6},
+ { 0xFFFF, 0, 0, 0, 0, 0},
+};
+
+static struct dibx000_agc_config dib7090_agc_config[2] = {
{
.band_caps = BAND_UHF,
/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
@@ -2278,6 +2587,34 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
}
};
+static struct dib7000p_config tfe7090e_dib7000p_config = {
+ .output_mpeg2_in_188_bytes = 1,
+ .hostbus_diversity = 1,
+ .tuner_is_baseband = 1,
+ .update_lna = dib7090e_update_lna,
+
+ .agc_config_count = 2,
+ .agc = dib7090_agc_config,
+
+ .bw = &dib7090_clock_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .pwm_freq_div = 0,
+
+ .agc_control = dib7090_agc_restart,
+
+ .spur_protect = 0,
+ .disable_sample_and_hold = 0,
+ .enable_current_mirror = 0,
+ .diversity_delay = 0,
+
+ .output_mode = OUTMODE_MPEG2_FIFO,
+ .enMpegOutput = 1,
+};
+
static const struct dib0090_config nim7090_dib0090_config = {
.io.clock_khz = 12000,
.io.pll_bypass = 0,
@@ -2312,6 +2649,107 @@ static const struct dib0090_config nim7090_dib0090_config = {
.in_soc = 1,
};
+static const struct dib0090_config tfe7090e_dib0090_config = {
+ .io.clock_khz = 12000,
+ .io.pll_bypass = 0,
+ .io.pll_range = 0,
+ .io.pll_prediv = 3,
+ .io.pll_loopdiv = 6,
+ .io.adc_clock_ratio = 0,
+ .io.pll_int_loop_filt = 0,
+ .reset = dib7090_tuner_sleep,
+ .sleep = dib7090_tuner_sleep,
+
+ .freq_offset_khz_uhf = 0,
+ .freq_offset_khz_vhf = 0,
+
+ .get_adc_power = dib7090_get_adc_power,
+
+ .clkouttobamse = 1,
+ .analog_output = 0,
+
+ .wbd_vhf_offset = 0,
+ .wbd_cband_offset = 0,
+ .use_pwm_agc = 1,
+ .clkoutdrive = 0,
+
+ .fref_clock_ratio = 0,
+
+ .wbd = dib7090e_wbd_table,
+
+ .ls_cfg_pad_drv = 0,
+ .data_tx_drv = 0,
+ .low_if = NULL,
+ .in_soc = 1,
+ .force_cband_input = 1,
+ .is_dib7090e = 1,
+};
+
+static struct dib7000p_config tfe7790e_dib7000p_config = {
+ .output_mpeg2_in_188_bytes = 1,
+ .hostbus_diversity = 1,
+ .tuner_is_baseband = 1,
+ .update_lna = dib7090e_update_lna,
+
+ .agc_config_count = 2,
+ .agc = dib7090_agc_config,
+
+ .bw = &dib7090_clock_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .pwm_freq_div = 0,
+
+ .agc_control = dib7090_agc_restart,
+
+ .spur_protect = 0,
+ .disable_sample_and_hold = 0,
+ .enable_current_mirror = 0,
+ .diversity_delay = 0,
+
+ .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK,
+ .enMpegOutput = 1,
+};
+
+static const struct dib0090_config tfe7790e_dib0090_config = {
+ .io.clock_khz = 12000,
+ .io.pll_bypass = 0,
+ .io.pll_range = 0,
+ .io.pll_prediv = 3,
+ .io.pll_loopdiv = 6,
+ .io.adc_clock_ratio = 0,
+ .io.pll_int_loop_filt = 0,
+ .reset = dib7090_tuner_sleep,
+ .sleep = dib7090_tuner_sleep,
+
+ .freq_offset_khz_uhf = 0,
+ .freq_offset_khz_vhf = 0,
+
+ .get_adc_power = dib7090_get_adc_power,
+
+ .clkouttobamse = 1,
+ .analog_output = 0,
+
+ .wbd_vhf_offset = 0,
+ .wbd_cband_offset = 0,
+ .use_pwm_agc = 1,
+ .clkoutdrive = 0,
+
+ .fref_clock_ratio = 0,
+
+ .wbd = dib7090e_wbd_table,
+
+ .ls_cfg_pad_drv = 0,
+ .data_tx_drv = 0,
+ .low_if = NULL,
+ .in_soc = 1,
+ .force_cband_input = 1,
+ .is_dib7090e = 1,
+ .force_crystal_mode = 1,
+};
+
static const struct dib0090_config tfe7090pvr_dib0090_config[2] = {
{
.io.clock_khz = 12000,
@@ -2504,6 +2942,97 @@ static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
return 0;
}
+static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(20);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+ msleep(20);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(20);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
+ 1, 0x10, &tfe7090e_dib7000p_config) != 0) {
+ err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ __func__);
+ return -ENODEV;
+ }
+ adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+ 0x80, &tfe7090e_dib7000p_config);
+
+ return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct dib0700_state *st = adap->dev->priv;
+
+ /* The TFE7790E requires the dib0700 to not be in master mode */
+ st->disable_streaming_master_mode = 1;
+
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(20);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+ msleep(20);
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(20);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
+ 1, 0x10, &tfe7790e_dib7000p_config) != 0) {
+ err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ __func__);
+ return -ENODEV;
+ }
+ adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+ 0x80, &tfe7790e_dib7000p_config);
+
+ return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+}
+
+static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dib0700_adapter_state *st = adap->priv;
+ struct i2c_adapter *tun_i2c =
+ dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+
+ if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
+ &tfe7790e_dib0090_config) == NULL)
+ return -ENODEV;
+
+ dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+ st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+ adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+ return 0;
+}
+
+static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dib0700_adapter_state *st = adap->priv;
+ struct i2c_adapter *tun_i2c =
+ dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+
+ if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
+ &tfe7090e_dib0090_config) == NULL)
+ return -ENODEV;
+
+ dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+ st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+ adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+ return 0;
+}
+
/* STK7070PD */
static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
{
@@ -2537,19 +3066,25 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
}
};
-static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+static void stk7070pd_init(struct dvb_usb_device *dev)
{
- dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ dib0700_set_gpio(dev, GPIO6, GPIO_OUT, 1);
msleep(10);
- dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+ dib0700_set_gpio(dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 0);
- dib0700_ctrl_clock(adap->dev, 72, 1);
+ dib0700_ctrl_clock(dev, 72, 1);
msleep(10);
- dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 1);
+}
+
+static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+{
+ stk7070pd_init(adap->dev);
+
msleep(10);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
@@ -2570,6 +3105,77 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
+static int novatd_read_status_override(struct dvb_frontend *fe,
+ fe_status_t *stat)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dvb_usb_device *dev = adap->dev;
+ struct dib0700_state *state = dev->priv;
+ int ret;
+
+ ret = state->read_status(fe, stat);
+
+ if (!ret)
+ dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT,
+ !!(*stat & FE_HAS_LOCK));
+
+ return ret;
+}
+
+static int novatd_sleep_override(struct dvb_frontend* fe)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dvb_usb_device *dev = adap->dev;
+ struct dib0700_state *state = dev->priv;
+
+ /* turn off LED */
+ dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT, 0);
+
+ return state->sleep(fe);
+}
+
+/**
+ * novatd_frontend_attach - Nova-TD specific attach
+ *
+ * Nova-TD has GPIO0, 1 and 2 for LEDs. So do not fiddle with them except for
+ * information purposes.
+ */
+static int novatd_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *dev = adap->dev;
+ struct dib0700_state *st = dev->priv;
+
+ if (adap->id == 0) {
+ stk7070pd_init(dev);
+
+ /* turn the power LED on, the other two off (just in case) */
+ dib0700_set_gpio(dev, GPIO0, GPIO_OUT, 0);
+ dib0700_set_gpio(dev, GPIO1, GPIO_OUT, 0);
+ dib0700_set_gpio(dev, GPIO2, GPIO_OUT, 1);
+
+ if (dib7000p_i2c_enumeration(&dev->i2c_adap, 2, 18,
+ stk7070pd_dib7000p_config) != 0) {
+ err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ __func__);
+ return -ENODEV;
+ }
+ }
+
+ adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &dev->i2c_adap,
+ adap->id == 0 ? 0x80 : 0x82,
+ &stk7070pd_dib7000p_config[adap->id]);
+
+ if (adap->fe_adap[0].fe == NULL)
+ return -ENODEV;
+
+ st->read_status = adap->fe_adap[0].fe->ops.read_status;
+ adap->fe_adap[0].fe->ops.read_status = novatd_read_status_override;
+ st->sleep = adap->fe_adap[0].fe->ops.sleep;
+ adap->fe_adap[0].fe->ops.sleep = novatd_sleep_override;
+
+ return 0;
+}
+
/* S5H1411 */
static struct s5h1411_config pinnacle_801e_config = {
.output_mode = S5H1411_PARALLEL_OUTPUT,
@@ -2960,6 +3566,9 @@ struct usb_device_id dib0700_usb_id_table[] = {
/* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) },
+/* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3338,6 +3947,57 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.pid_filter_count = 32,
.pid_filter = stk70x0p_pid_filter,
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+ .frontend_attach = novatd_frontend_attach,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+ }},
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }, {
+ .num_frontends = 1,
+ .fe = {{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk70x0p_pid_filter,
+ .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+ .frontend_attach = novatd_frontend_attach,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+ }},
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Hauppauge Nova-TD Stick (52009)",
+ { &dib0700_usb_id_table[35], NULL },
+ { NULL },
+ },
+ },
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 2,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk70x0p_pid_filter,
+ .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
.frontend_attach = stk7070pd_frontend_attach0,
.tuner_attach = dib7070p_tuner_attach,
@@ -3360,7 +4020,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .num_device_descs = 6,
+ .num_device_descs = 5,
.devices = {
{ "DiBcom STK7070PD reference design",
{ &dib0700_usb_id_table[17], NULL },
@@ -3370,10 +4030,6 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[18], NULL },
{ NULL },
},
- { "Hauppauge Nova-TD Stick (52009)",
- { &dib0700_usb_id_table[35], NULL },
- { NULL },
- },
{ "Hauppauge Nova-TD-500 (84xxx)",
{ &dib0700_usb_id_table[36], NULL },
{ NULL },
@@ -4025,6 +4681,127 @@ struct dvb_usb_device_properties dib0700_devices[] = {
RC_TYPE_NEC,
.change_protocol = dib0700_change_protocol,
},
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk70x0p_pid_filter,
+ .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+ .frontend_attach = tfe7090e_frontend_attach,
+ .tuner_attach = tfe7090e_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+ } },
+
+ .size_of_priv =
+ sizeof(struct dib0700_adapter_state),
+ },
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "DiBcom TFE7090E reference design",
+ { &dib0700_usb_id_table[78], NULL },
+ { NULL },
+ },
+ },
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk70x0p_pid_filter,
+ .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+ .frontend_attach = tfe7790e_frontend_attach,
+ .tuner_attach = tfe7790e_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+ } },
+
+ .size_of_priv =
+ sizeof(struct dib0700_adapter_state),
+ },
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "DiBcom TFE7790E reference design",
+ { &dib0700_usb_id_table[79], NULL },
+ { NULL },
+ },
+ },
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk80xx_pid_filter,
+ .pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+ .frontend_attach = tfe8096p_frontend_attach,
+ .tuner_attach = tfe8096p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+ } },
+
+ .size_of_priv =
+ sizeof(struct dib0700_adapter_state),
+ },
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "DiBcom TFE8096P reference design",
+ { &dib0700_usb_id_table[80], NULL },
+ { NULL },
+ },
+ },
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
},
};
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 0a9a79820f26..ff34419a4c88 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -118,12 +118,12 @@ static struct mt352_config digitv_mt352_config = {
.demod_init = digitv_mt352_demod_init,
};
-static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
u8 b[5];
- fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b));
+ fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b));
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
index 17413adec7a1..3d81daa49172 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
@@ -16,7 +16,7 @@ struct dtt200u_fe_state {
fe_status_t stat;
- struct dvb_frontend_parameters fep;
+ struct dtv_frontend_properties fep;
struct dvb_frontend frontend;
};
@@ -100,22 +100,27 @@ static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_fron
return 0;
}
-static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static int dtt200u_fe_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dtt200u_fe_state *state = fe->demodulator_priv;
int i;
fe_status_t st;
u16 freq = fep->frequency / 250000;
u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 };
- switch (fep->u.ofdm.bandwidth) {
- case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break;
- case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break;
- case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break;
- case BANDWIDTH_AUTO: return -EOPNOTSUPP;
- default:
- return -EINVAL;
+ switch (fep->bandwidth_hz) {
+ case 8000000:
+ bwbuf[1] = 8;
+ break;
+ case 7000000:
+ bwbuf[1] = 7;
+ break;
+ case 6000000:
+ bwbuf[1] = 6;
+ break;
+ default:
+ return -EINVAL;
}
dvb_usb_generic_write(state->d,bwbuf,2);
@@ -134,11 +139,11 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
return 0;
}
-static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static int dtt200u_fe_get_frontend(struct dvb_frontend* fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dtt200u_fe_state *state = fe->demodulator_priv;
- memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters));
+ memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties));
return 0;
}
@@ -172,9 +177,9 @@ error:
}
static struct dvb_frontend_ops dtt200u_fe_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "WideView USB DVB-T",
- .type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 250000,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index ba4a7517354f..ddf282f355b3 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -141,11 +141,17 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
goto err_dmx_dev;
}
- dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+ if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net,
+ &adap->demux.dmx)) < 0) {
+ err("dvb_net_init failed: error %d",ret);
+ goto err_net_init;
+ }
adap->state |= DVB_USB_ADAP_STATE_DVB;
return 0;
+err_net_init:
+ dvb_dmxdev_release(&adap->dmxdev);
err_dmx_dev:
dvb_dmx_release(&adap->demux);
err_dmx:
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 2d08c9b5128a..397d8f232731 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -51,6 +51,7 @@
#define USB_VID_PINNACLE 0x2304
#define USB_VID_PCTV 0x2013
#define USB_VID_PIXELVIEW 0x1554
+#define USB_VID_REALTEK 0x0bda
#define USB_VID_TECHNOTREND 0x0b48
#define USB_VID_TERRATEC 0x0ccd
#define USB_VID_TELESTAR 0x10b9
@@ -80,6 +81,7 @@
#define USB_PID_ANSONIC_DVBT_USB 0x6000
#define USB_PID_ANYSEE 0x861f
#define USB_PID_AZUREWAVE_AD_TU700 0x3237
+#define USB_PID_AZUREWAVE_6007 0x0ccd
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
@@ -109,10 +111,13 @@
#define USB_PID_DIBCOM_STK807XPVR 0x1f98
#define USB_PID_DIBCOM_STK8096GP 0x1fa0
#define USB_PID_DIBCOM_NIM8096MD 0x1fa8
+#define USB_PID_DIBCOM_TFE8096P 0x1f9C
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
#define USB_PID_DIBCOM_STK7770P 0x1e80
#define USB_PID_DIBCOM_NIM7090 0x1bb2
#define USB_PID_DIBCOM_TFE7090PVR 0x1bb4
+#define USB_PID_DIBCOM_TFE7090E 0x1bb7
+#define USB_PID_DIBCOM_TFE7790E 0x1e6e
#define USB_PID_DIBCOM_NIM9090M 0x2383
#define USB_PID_DIBCOM_NIM9090MD 0x2384
#define USB_PID_DPOSH_M9206_COLD 0x9206
@@ -122,12 +127,16 @@
#define USB_PID_E3C_EC168_3 0xfffb
#define USB_PID_E3C_EC168_4 0x1001
#define USB_PID_E3C_EC168_5 0x1002
+#define USB_PID_FREECOM_DVBT 0x0160
+#define USB_PID_FREECOM_DVBT_2 0x0161
#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_WARM 0x0fa1
#define USB_PID_INTEL_CE9500 0x9500
#define USB_PID_ITETECH_IT9135 0x9135
+#define USB_PID_ITETECH_IT9135_9005 0x9005
+#define USB_PID_ITETECH_IT9135_9006 0x9006
#define USB_PID_KWORLD_399U 0xe399
#define USB_PID_KWORLD_399U_2 0xe400
#define USB_PID_KWORLD_395U 0xe396
@@ -221,6 +230,8 @@
#define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062
#define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078
#define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab
+#define USB_PID_TERRATEC_H7 0x10b4
+#define USB_PID_TERRATEC_H7_2 0x10a3
#define USB_PID_TERRATEC_T3 0x10a0
#define USB_PID_TERRATEC_T5 0x10a1
#define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e
@@ -244,6 +255,8 @@
#define USB_PID_PCTV_400E 0x020f
#define USB_PID_PCTV_450E 0x0222
#define USB_PID_PCTV_452E 0x021f
+#define USB_PID_REALTEK_RTL2831U 0x2831
+#define USB_PID_REALTEK_RTL2832U 0x2832
#define USB_PID_TECHNOTREND_CONNECT_S2_3600 0x3007
#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI 0x300a
#define USB_PID_NEBULA_DIGITV 0x0201
@@ -322,6 +335,7 @@
#define USB_PID_TVWAY_PLUS 0x0002
#define USB_PID_SVEON_STV20 0xe39d
#define USB_PID_SVEON_STV22 0xe401
+#define USB_PID_SVEON_STV22_IT9137 0xe411
#define USB_PID_AZUREWAVE_AZ6027 0x3275
#define USB_PID_TERRATEC_DVBS2CI_V1 0x10a4
#define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index ff941d20e6b7..451c5a7adfb2 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -1435,22 +1435,40 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
+enum dw2102_table_entry {
+ CYPRESS_DW2102,
+ CYPRESS_DW2101,
+ CYPRESS_DW2104,
+ TEVII_S650,
+ TERRATEC_CINERGY_S,
+ CYPRESS_DW3101,
+ TEVII_S630,
+ PROF_1100,
+ TEVII_S660,
+ PROF_7500,
+ GENIATECH_SU3000,
+ TERRATEC_CINERGY_S2,
+ TEVII_S480_1,
+ TEVII_S480_2,
+ X3M_SPC1400HD,
+};
+
static struct usb_device_id dw2102_table[] = {
- {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
- {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
- {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_CYPRESS, USB_PID_DW3101)},
- {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
- {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
- {USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
- {USB_DEVICE(0x3034, 0x7500)},
- {USB_DEVICE(0x1f4d, 0x3000)},
- {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)},
- {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
- {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
- {USB_DEVICE(0x1f4d, 0x3100)},
+ [CYPRESS_DW2102] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
+ [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
+ [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
+ [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
+ [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
+ [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
+ [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
+ [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
+ [TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
+ [PROF_7500] = {USB_DEVICE(0x3034, 0x7500)},
+ [GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)},
+ [TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)},
+ [TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
+ [TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
+ [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
{ }
};
@@ -1610,15 +1628,15 @@ static struct dvb_usb_device_properties dw2102_properties = {
.num_device_descs = 3,
.devices = {
{"DVBWorld DVB-S 2102 USB2.0",
- {&dw2102_table[0], NULL},
+ {&dw2102_table[CYPRESS_DW2102], NULL},
{NULL},
},
{"DVBWorld DVB-S 2101 USB2.0",
- {&dw2102_table[1], NULL},
+ {&dw2102_table[CYPRESS_DW2101], NULL},
{NULL},
},
{"TerraTec Cinergy S USB",
- {&dw2102_table[4], NULL},
+ {&dw2102_table[TERRATEC_CINERGY_S], NULL},
{NULL},
},
}
@@ -1664,11 +1682,11 @@ static struct dvb_usb_device_properties dw2104_properties = {
.num_device_descs = 2,
.devices = {
{ "DVBWorld DW2104 USB2.0",
- {&dw2102_table[2], NULL},
+ {&dw2102_table[CYPRESS_DW2104], NULL},
{NULL},
},
{ "TeVii S650 USB2.0",
- {&dw2102_table[3], NULL},
+ {&dw2102_table[TEVII_S650], NULL},
{NULL},
},
}
@@ -1715,7 +1733,7 @@ static struct dvb_usb_device_properties dw3101_properties = {
.num_device_descs = 1,
.devices = {
{ "DVBWorld DVB-C 3101 USB2.0",
- {&dw2102_table[5], NULL},
+ {&dw2102_table[CYPRESS_DW3101], NULL},
{NULL},
},
}
@@ -1761,7 +1779,7 @@ static struct dvb_usb_device_properties s6x0_properties = {
.num_device_descs = 1,
.devices = {
{"TeVii S630 USB",
- {&dw2102_table[6], NULL},
+ {&dw2102_table[TEVII_S630], NULL},
{NULL},
},
}
@@ -1770,33 +1788,33 @@ static struct dvb_usb_device_properties s6x0_properties = {
struct dvb_usb_device_properties *p1100;
static struct dvb_usb_device_description d1100 = {
"Prof 1100 USB ",
- {&dw2102_table[7], NULL},
+ {&dw2102_table[PROF_1100], NULL},
{NULL},
};
struct dvb_usb_device_properties *s660;
static struct dvb_usb_device_description d660 = {
"TeVii S660 USB",
- {&dw2102_table[8], NULL},
+ {&dw2102_table[TEVII_S660], NULL},
{NULL},
};
static struct dvb_usb_device_description d480_1 = {
"TeVii S480.1 USB",
- {&dw2102_table[12], NULL},
+ {&dw2102_table[TEVII_S480_1], NULL},
{NULL},
};
static struct dvb_usb_device_description d480_2 = {
"TeVii S480.2 USB",
- {&dw2102_table[13], NULL},
+ {&dw2102_table[TEVII_S480_2], NULL},
{NULL},
};
struct dvb_usb_device_properties *p7500;
static struct dvb_usb_device_description d7500 = {
"Prof 7500 USB DVB-S2",
- {&dw2102_table[9], NULL},
+ {&dw2102_table[PROF_7500], NULL},
{NULL},
};
@@ -1842,15 +1860,15 @@ static struct dvb_usb_device_properties su3000_properties = {
.num_device_descs = 3,
.devices = {
{ "SU3000HD DVB-S USB2.0",
- { &dw2102_table[10], NULL },
+ { &dw2102_table[GENIATECH_SU3000], NULL },
{ NULL },
},
{ "Terratec Cinergy S2 USB HD",
- { &dw2102_table[11], NULL },
+ { &dw2102_table[TERRATEC_CINERGY_S2], NULL },
{ NULL },
},
{ "X3M TV SPC1400HD PCI",
- { &dw2102_table[14], NULL },
+ { &dw2102_table[X3M_SPC1400HD], NULL },
{ NULL },
},
}
@@ -1859,12 +1877,11 @@ static struct dvb_usb_device_properties su3000_properties = {
static int dw2102_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- p1100 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+ p1100 = kmemdup(&s6x0_properties,
+ sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
if (!p1100)
return -ENOMEM;
/* copy default structure */
- memcpy(p1100, &s6x0_properties,
- sizeof(struct dvb_usb_device_properties));
/* fill only different fields */
p1100->firmware = "dvb-usb-p1100.fw";
p1100->devices[0] = d1100;
@@ -1872,13 +1889,12 @@ static int dw2102_probe(struct usb_interface *intf,
p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach;
- s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+ s660 = kmemdup(&s6x0_properties,
+ sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
if (!s660) {
kfree(p1100);
return -ENOMEM;
}
- memcpy(s660, &s6x0_properties,
- sizeof(struct dvb_usb_device_properties));
s660->firmware = "dvb-usb-s660.fw";
s660->num_device_descs = 3;
s660->devices[0] = d660;
@@ -1886,14 +1902,13 @@ static int dw2102_probe(struct usb_interface *intf,
s660->devices[2] = d480_2;
s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach;
- p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+ p7500 = kmemdup(&s6x0_properties,
+ sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
if (!p7500) {
kfree(p1100);
kfree(s660);
return -ENOMEM;
}
- memcpy(p7500, &s6x0_properties,
- sizeof(struct dvb_usb_device_properties));
p7500->firmware = "dvb-usb-p7500.fw";
p7500->devices[0] = d7500;
p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c
index 015b4e8af1a5..90a70c66a96e 100644
--- a/drivers/media/dvb/dvb-usb/friio-fe.c
+++ b/drivers/media/dvb/dvb-usb/friio-fe.c
@@ -282,23 +282,24 @@ static int jdvbt90502_set_property(struct dvb_frontend *fe,
return r;
}
-static int jdvbt90502_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int jdvbt90502_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
p->inversion = INVERSION_AUTO;
- p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
- p->u.ofdm.code_rate_HP = FEC_AUTO;
- p->u.ofdm.code_rate_LP = FEC_AUTO;
- p->u.ofdm.constellation = QAM_64;
- p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
- p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
- p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
+ p->bandwidth_hz = 6000000;
+ p->code_rate_HP = FEC_AUTO;
+ p->code_rate_LP = FEC_AUTO;
+ p->modulation = QAM_64;
+ p->transmission_mode = TRANSMISSION_MODE_AUTO;
+ p->guard_interval = GUARD_INTERVAL_AUTO;
+ p->hierarchy = HIERARCHY_AUTO;
return 0;
}
-static int jdvbt90502_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int jdvbt90502_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
/**
* NOTE: ignore all the parameters except frequency.
* others should be fixed to the proper value for ISDB-T,
@@ -438,14 +439,12 @@ error:
}
static struct dvb_frontend_ops jdvbt90502_ops = {
-
+ .delsys = { SYS_ISDBT },
.info = {
.name = "Comtech JDVBT90502 ISDB-T",
- .type = FE_OFDM,
.frequency_min = 473000000, /* UHF 13ch, center */
.frequency_max = 767142857, /* UHF 62ch, center */
- .frequency_stepsize = JDVBT90502_PLL_CLK /
- JDVBT90502_PLL_DIVIDER,
+ .frequency_stepsize = JDVBT90502_PLL_CLK / JDVBT90502_PLL_DIVIDER,
.frequency_tolerance = 0,
/* NOTE: this driver ignores all parameters but frequency. */
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index 5426267980c7..67957dd99ede 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -113,28 +113,12 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
return 0;
}
-static int gp8psk_fe_set_property(struct dvb_frontend *fe,
- struct dtv_property *tvp)
-{
- deb_fe("%s(..)\n", __func__);
- return 0;
-}
-
-static int gp8psk_fe_get_property(struct dvb_frontend *fe,
- struct dtv_property *tvp)
-{
- deb_fe("%s(..)\n", __func__);
- return 0;
-}
-
-
-static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static int gp8psk_fe_set_frontend(struct dvb_frontend *fe)
{
struct gp8psk_fe_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u8 cmd[10];
- u32 freq = fep->frequency * 1000;
+ u32 freq = c->frequency * 1000;
int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
deb_fe("%s()\n", __func__);
@@ -342,9 +326,9 @@ success:
static struct dvb_frontend_ops gp8psk_fe_ops = {
+ .delsys = { SYS_DVBS },
.info = {
.name = "Genpix DVB-S",
- .type = FE_QPSK,
.frequency_min = 800000,
.frequency_max = 2250000,
.frequency_stepsize = 100,
@@ -366,8 +350,6 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
.init = NULL,
.sleep = NULL,
- .set_property = gp8psk_fe_set_property,
- .get_property = gp8psk_fe_get_property,
.set_frontend = gp8psk_fe_set_frontend,
.get_tune_settings = gp8psk_fe_get_tune_settings,
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c
index 67094b879bb4..482d249ca7f3 100644
--- a/drivers/media/dvb/dvb-usb/it913x.c
+++ b/drivers/media/dvb/dvb-usb/it913x.c
@@ -52,42 +52,60 @@ static int pid_filter;
module_param_named(pid, pid_filter, int, 0644);
MODULE_PARM_DESC(pid, "set default 0=on 1=off");
+static int dvb_usb_it913x_firmware;
+module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644);
+MODULE_PARM_DESC(firmware, "set firmware 0=auto 1=IT9137 2=IT9135V1");
+
+
int cmd_counter;
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct it913x_state {
u8 id;
-};
-
-struct ite_config {
- u8 chip_ver;
- u16 chip_type;
- u32 firmware;
- u8 tuner_id_0;
- u8 tuner_id_1;
- u8 dual_mode;
+ struct ite_config it913x_config;
+ u8 pid_filter_onoff;
};
struct ite_config it913x_config;
+#define IT913X_RETRY 10
+#define IT913X_SND_TIMEOUT 100
+#define IT913X_RCV_TIMEOUT 200
+
static int it913x_bulk_write(struct usb_device *dev,
u8 *snd, int len, u8 pipe)
{
- int ret, actual_l;
+ int ret, actual_l, i;
+
+ for (i = 0; i < IT913X_RETRY; i++) {
+ ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
+ snd, len , &actual_l, IT913X_SND_TIMEOUT);
+ if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT)
+ break;
+ }
+
+ if (len != actual_l && ret == 0)
+ ret = -EAGAIN;
- ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
- snd, len , &actual_l, 100);
return ret;
}
static int it913x_bulk_read(struct usb_device *dev,
u8 *rev, int len, u8 pipe)
{
- int ret, actual_l;
+ int ret, actual_l, i;
+
+ for (i = 0; i < IT913X_RETRY; i++) {
+ ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
+ rev, len , &actual_l, IT913X_RCV_TIMEOUT);
+ if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT)
+ break;
+ }
+
+ if (len != actual_l && ret == 0)
+ ret = -EAGAIN;
- ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
- rev, len , &actual_l, 200);
return ret;
}
@@ -100,7 +118,7 @@ static u16 check_sum(u8 *p, u8 len)
return ~sum;
}
-static int it913x_io(struct usb_device *udev, u8 mode, u8 pro,
+static int it913x_usb_talk(struct usb_device *udev, u8 mode, u8 pro,
u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
{
int ret = 0, i, buf_size = 1;
@@ -159,22 +177,41 @@ static int it913x_io(struct usb_device *udev, u8 mode, u8 pro,
buff[buf_size++] = (chk_sum & 0xff);
ret = it913x_bulk_write(udev, buff, buf_size , 0x02);
+ if (ret < 0)
+ goto error;
- ret |= it913x_bulk_read(udev, buff, (mode & 1) ?
+ ret = it913x_bulk_read(udev, buff, (mode & 1) ?
5 : len + 5 , 0x01);
+ if (ret < 0)
+ goto error;
rlen = (mode & 0x1) ? 0x1 : len;
if (mode & 1)
- ret |= buff[2];
+ ret = buff[2];
else
memcpy(data, &buff[3], rlen);
cmd_counter++;
- kfree(buff);
+error: kfree(buff);
- return (ret < 0) ? -ENODEV : 0;
+ return ret;
+}
+
+static int it913x_io(struct usb_device *udev, u8 mode, u8 pro,
+ u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
+{
+ int ret, i;
+
+ for (i = 0; i < IT913X_RETRY; i++) {
+ ret = it913x_usb_talk(udev, mode, pro,
+ cmd, reg, addr, data, len);
+ if (ret != -EAGAIN)
+ break;
+ }
+
+ return ret;
}
static int it913x_wr_reg(struct usb_device *udev, u8 pro, u32 reg , u8 data)
@@ -201,12 +238,27 @@ static int it913x_read_reg(struct usb_device *udev, u32 reg)
static u32 it913x_query(struct usb_device *udev, u8 pro)
{
- int ret;
+ int ret, i;
u8 data[4];
- ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ,
- 0x1222, 0, &data[0], 3);
+ u8 ver;
+
+ for (i = 0; i < 5; i++) {
+ ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ,
+ 0x1222, 0, &data[0], 3);
+ ver = data[0];
+ if (ver > 0 && ver < 3)
+ break;
+ msleep(100);
+ }
- it913x_config.chip_ver = data[0];
+ if (ver < 1 || ver > 2) {
+ info("Failed to identify chip version applying 1");
+ it913x_config.chip_ver = 0x1;
+ it913x_config.chip_type = 0x9135;
+ return 0;
+ }
+
+ it913x_config.chip_ver = ver;
it913x_config.chip_type = (u16)(data[2] << 8) + data[1];
info("Chip Version=%02x Chip Type=%04x", it913x_config.chip_ver,
@@ -223,15 +275,16 @@ static u32 it913x_query(struct usb_device *udev, u8 pro)
static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
- int ret = 0;
+ struct it913x_state *st = adap->dev->priv;
+ struct usb_device *udev = adap->dev->udev;
+ int ret;
u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
- return -EAGAIN;
+ mutex_lock(&adap->dev->i2c_mutex);
+
deb_info(1, "PID_C (%02x)", onoff);
- if (!onoff)
- ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1);
+ ret = it913x_wr_reg(udev, pro, PID_EN, st->pid_filter_onoff);
mutex_unlock(&adap->dev->i2c_mutex);
return ret;
@@ -240,28 +293,29 @@ static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
static int it913x_pid_filter(struct dvb_usb_adapter *adap,
int index, u16 pid, int onoff)
{
+ struct it913x_state *st = adap->dev->priv;
struct usb_device *udev = adap->dev->udev;
- int ret = 0;
+ int ret;
u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
- if (pid_filter > 0)
- return 0;
+ mutex_lock(&adap->dev->i2c_mutex);
- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
- return -EAGAIN;
deb_info(1, "PID_F (%02x)", onoff);
- if (onoff) {
- ret = it913x_wr_reg(udev, pro, PID_EN, 0x1);
- ret |= it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff));
+ ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff));
- ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8));
+ ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8));
- ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff);
+ ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff);
- ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f));
+ ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f));
- }
+ if (udev->speed == USB_SPEED_HIGH && pid == 0x2000) {
+ ret |= it913x_wr_reg(udev, pro, PID_EN, !onoff);
+ st->pid_filter_onoff = !onoff;
+ } else
+ st->pid_filter_onoff =
+ adap->fe_adap[adap->active_fe].pid_filtering;
mutex_unlock(&adap->dev->i2c_mutex);
return 0;
@@ -287,8 +341,8 @@ static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int ret;
u32 reg;
u8 pro;
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
+
+ mutex_lock(&d->i2c_mutex);
debug_data_snipet(1, "Message out", msg[0].buf);
deb_info(2, "num of messages %d address %02x", num, msg[0].addr);
@@ -329,46 +383,203 @@ static int it913x_rc_query(struct dvb_usb_device *d)
int ret;
u32 key;
/* Avoid conflict with frontends*/
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
+ mutex_lock(&d->i2c_mutex);
ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET,
0, 0, &ibuf[0], sizeof(ibuf));
if ((ibuf[2] + ibuf[3]) == 0xff) {
key = ibuf[2];
- key += ibuf[0] << 8;
- deb_info(1, "INT Key =%08x", key);
+ key += ibuf[0] << 16;
+ key += ibuf[1] << 8;
+ deb_info(1, "NEC Extended Key =%08x", key);
if (d->rc_dev != NULL)
rc_keydown(d->rc_dev, key, 0);
}
+
mutex_unlock(&d->i2c_mutex);
return ret;
}
+
+/* Firmware sets raw */
+const char fw_it9135_v1[] = "dvb-usb-it9135-01.fw";
+const char fw_it9135_v2[] = "dvb-usb-it9135-02.fw";
+const char fw_it9137[] = "dvb-usb-it9137-01.fw";
+
+static int ite_firmware_select(struct usb_device *udev,
+ struct dvb_usb_device_properties *props)
+{
+ int sw;
+ /* auto switch */
+ if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_KWORLD_2)
+ sw = IT9137_FW;
+ else if (it913x_config.chip_ver == 1)
+ sw = IT9135_V1_FW;
+ else
+ sw = IT9135_V2_FW;
+
+ /* force switch */
+ if (dvb_usb_it913x_firmware != IT9135_AUTO)
+ sw = dvb_usb_it913x_firmware;
+
+ switch (sw) {
+ case IT9135_V1_FW:
+ it913x_config.firmware_ver = 1;
+ it913x_config.adc_x2 = 1;
+ it913x_config.read_slevel = false;
+ props->firmware = fw_it9135_v1;
+ break;
+ case IT9135_V2_FW:
+ it913x_config.firmware_ver = 1;
+ it913x_config.adc_x2 = 1;
+ it913x_config.read_slevel = false;
+ props->firmware = fw_it9135_v2;
+ switch (it913x_config.tuner_id_0) {
+ case IT9135_61:
+ case IT9135_62:
+ break;
+ default:
+ info("Unknown tuner ID applying default 0x60");
+ case IT9135_60:
+ it913x_config.tuner_id_0 = IT9135_60;
+ }
+ break;
+ case IT9137_FW:
+ default:
+ it913x_config.firmware_ver = 0;
+ it913x_config.adc_x2 = 0;
+ it913x_config.read_slevel = true;
+ props->firmware = fw_it9137;
+ }
+
+ return 0;
+}
+
+static void it913x_select_remote(struct usb_device *udev,
+ struct dvb_usb_device_properties *props)
+{
+ switch (le16_to_cpu(udev->descriptor.idProduct)) {
+ case USB_PID_ITETECH_IT9135_9005:
+ props->rc.core.rc_codes = RC_MAP_IT913X_V2;
+ return;
+ default:
+ props->rc.core.rc_codes = RC_MAP_IT913X_V1;
+ }
+ return;
+}
+
+#define TS_MPEG_PKT_SIZE 188
+#define EP_LOW 21
+#define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE)
+#define EP_HIGH 348
+#define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE)
+
+static int it913x_select_config(struct usb_device *udev,
+ struct dvb_usb_device_properties *props)
+{
+ int ret = 0, reg;
+ bool proprietary_ir = false;
+
+ if (it913x_config.chip_ver == 0x02
+ && it913x_config.chip_type == 0x9135)
+ reg = it913x_read_reg(udev, 0x461d);
+ else
+ reg = it913x_read_reg(udev, 0x461b);
+
+ if (reg < 0)
+ return reg;
+
+ if (reg == 0) {
+ it913x_config.dual_mode = 0;
+ it913x_config.tuner_id_0 = IT9135_38;
+ proprietary_ir = true;
+ } else {
+ /* TS mode */
+ reg = it913x_read_reg(udev, 0x49c5);
+ if (reg < 0)
+ return reg;
+ it913x_config.dual_mode = reg;
+
+ /* IR mode type */
+ reg = it913x_read_reg(udev, 0x49ac);
+ if (reg < 0)
+ return reg;
+ if (reg == 5) {
+ info("Remote propriety (raw) mode");
+ proprietary_ir = true;
+ } else if (reg == 1) {
+ info("Remote HID mode NOT SUPPORTED");
+ proprietary_ir = false;
+ props->rc.core.rc_codes = NULL;
+ } else
+ props->rc.core.rc_codes = NULL;
+
+ /* Tuner_id */
+ reg = it913x_read_reg(udev, 0x49d0);
+ if (reg < 0)
+ return reg;
+ it913x_config.tuner_id_0 = reg;
+ }
+
+ if (proprietary_ir)
+ it913x_select_remote(udev, props);
+
+ if (udev->speed != USB_SPEED_HIGH) {
+ props->adapter[0].fe[0].pid_filter_count = 5;
+ info("USB 1 low speed mode - connect to USB 2 port");
+ if (pid_filter > 0)
+ pid_filter = 0;
+ if (it913x_config.dual_mode) {
+ it913x_config.dual_mode = 0;
+ info("Dual mode not supported in USB 1");
+ }
+ } else /* For replugging */
+ if(props->adapter[0].fe[0].pid_filter_count == 5)
+ props->adapter[0].fe[0].pid_filter_count = 31;
+
+ /* Select Stream Buffer Size and pid filter option*/
+ if (pid_filter) {
+ props->adapter[0].fe[0].stream.u.bulk.buffersize =
+ TS_BUFFER_SIZE_MAX;
+ props->adapter[0].fe[0].caps &=
+ ~DVB_USB_ADAP_NEED_PID_FILTERING;
+ } else
+ props->adapter[0].fe[0].stream.u.bulk.buffersize =
+ TS_BUFFER_SIZE_PID;
+
+ if (it913x_config.dual_mode) {
+ props->adapter[1].fe[0].stream.u.bulk.buffersize =
+ props->adapter[0].fe[0].stream.u.bulk.buffersize;
+ props->num_adapters = 2;
+ if (pid_filter)
+ props->adapter[1].fe[0].caps =
+ props->adapter[0].fe[0].caps;
+ } else
+ props->num_adapters = 1;
+
+ info("Dual mode=%x Tuner Type=%x", it913x_config.dual_mode,
+ it913x_config.tuner_id_0);
+
+ ret = ite_firmware_select(udev, props);
+
+ return ret;
+}
+
static int it913x_identify_state(struct usb_device *udev,
struct dvb_usb_device_properties *props,
struct dvb_usb_device_description **desc,
int *cold)
{
int ret = 0, firm_no;
- u8 reg, remote;
+ u8 reg;
firm_no = it913x_return_status(udev);
- /* checnk for dual mode */
- it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5);
-
- /* TODO different remotes */
- remote = it913x_read_reg(udev, 0x49ac); /* Remote */
- if (remote == 0)
- props->rc.core.rc_codes = NULL;
-
- /* TODO at the moment tuner_id is always assigned to 0x38 */
- it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0);
-
- info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode
- , remote, it913x_config.tuner_id_0);
+ /* Read and select config */
+ ret = it913x_select_config(udev, props);
+ if (ret < 0)
+ return ret;
if (firm_no > 0) {
*cold = 0;
@@ -391,18 +602,22 @@ static int it913x_identify_state(struct usb_device *udev,
ret = it913x_wr_reg(udev, DEV_0,
GPIOH1_O, 0x0);
}
- props->num_adapters = 2;
- } else
- props->num_adapters = 1;
+ }
reg = it913x_read_reg(udev, IO_MUX_POWER_CLK);
if (it913x_config.dual_mode) {
ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
- ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1);
+ if (it913x_config.firmware_ver == 1)
+ ret |= it913x_wr_reg(udev, DEV_0, 0xcfff, 0x1);
+ else
+ ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1);
} else {
ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, 0x0);
- ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0);
+ if (it913x_config.firmware_ver == 1)
+ ret |= it913x_wr_reg(udev, DEV_0, 0xcfff, 0x0);
+ else
+ ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0);
}
*cold = 1;
@@ -412,74 +627,104 @@ static int it913x_identify_state(struct usb_device *udev,
static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
+ struct it913x_state *st = adap->dev->priv;
int ret = 0;
u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
- return -EAGAIN;
deb_info(1, "STM (%02x)", onoff);
- if (!onoff)
+ if (!onoff) {
+ mutex_lock(&adap->dev->i2c_mutex);
+
ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1);
+ mutex_unlock(&adap->dev->i2c_mutex);
+ st->pid_filter_onoff =
+ adap->fe_adap[adap->active_fe].pid_filtering;
- mutex_unlock(&adap->dev->i2c_mutex);
+ }
return ret;
}
-
static int it913x_download_firmware(struct usb_device *udev,
const struct firmware *fw)
{
- int ret = 0, i;
- u8 packet_size, dlen;
+ int ret = 0, i = 0, pos = 0;
+ u8 packet_size, min_pkt;
u8 *fw_data;
- packet_size = 0x29;
-
ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100);
info("FRM Starting Firmware Download");
- /* This uses scatter write firmware headers follow */
- /* 03 XX 00 XX = chip number? */
-
- for (i = 0; i < fw->size; i += packet_size) {
- if (i > 0)
- packet_size = 0x39;
- fw_data = (u8 *)(fw->data + i);
- dlen = ((i + packet_size) > fw->size)
- ? (fw->size - i) : packet_size;
- ret |= it913x_io(udev, WRITE_DATA, DEV_0,
- CMD_SCATTER_WRITE, 0, 0, fw_data, dlen);
- udelay(1000);
- }
- ret |= it913x_io(udev, WRITE_CMD, DEV_0,
- CMD_BOOT, 0, 0, NULL, 0);
+ /* Multi firmware loader */
+ /* This uses scatter write firmware headers */
+ /* The firmware must start with 03 XX 00 */
+ /* and be the extact firmware length */
- msleep(100);
+ if (it913x_config.chip_ver == 2)
+ min_pkt = 0x11;
+ else
+ min_pkt = 0x19;
+
+ while (i <= fw->size) {
+ if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0))
+ || (i == fw->size)) {
+ packet_size = i - pos;
+ if ((packet_size > min_pkt) || (i == fw->size)) {
+ fw_data = (u8 *)(fw->data + pos);
+ pos += packet_size;
+ if (packet_size > 0) {
+ ret = it913x_io(udev, WRITE_DATA,
+ DEV_0, CMD_SCATTER_WRITE, 0,
+ 0, fw_data, packet_size);
+ if (ret < 0)
+ break;
+ }
+ udelay(1000);
+ }
+ }
+ i++;
+ }
if (ret < 0)
- info("FRM Firmware Download Failed (%04x)" , ret);
+ info("FRM Firmware Download Failed (%d)" , ret);
else
info("FRM Firmware Download Completed - Resetting Device");
- ret |= it913x_return_status(udev);
+ msleep(30);
+
+ ret = it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0);
+ if (ret < 0)
+ info("FRM Device not responding to reboot");
+
+ ret = it913x_return_status(udev);
+ if (ret == 0) {
+ info("FRM Failed to reboot device");
+ return -ENODEV;
+ }
msleep(30);
- ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400);
+ ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400);
+
+ msleep(30);
/* Tuner function */
if (it913x_config.dual_mode)
ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0);
-
- ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0);
- ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0);
- if (it913x_config.dual_mode) {
- ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0);
- ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0);
+ else
+ ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0x68);
+
+ if ((it913x_config.chip_ver == 1) &&
+ (it913x_config.chip_type == 0x9135)) {
+ ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0);
+ ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0);
+ if (it913x_config.dual_mode) {
+ ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0);
+ ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0);
+ }
}
return (ret < 0) ? -ENODEV : 0;
@@ -500,32 +745,23 @@ static int it913x_name(struct dvb_usb_adapter *adap)
static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
{
struct usb_device *udev = adap->dev->udev;
+ struct it913x_state *st = adap->dev->priv;
int ret = 0;
- u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK);
u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
- u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize;
- u8 tuner_id, tuner_type;
+ u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize / 4;
+ u8 pkt_size = 0x80;
+
+ if (adap->dev->udev->speed != USB_SPEED_HIGH)
+ pkt_size = 0x10;
+
+ it913x_config.adf = it913x_read_reg(udev, IO_MUX_POWER_CLK);
if (adap->id == 0)
- tuner_id = it913x_config.tuner_id_0;
- else
- tuner_id = it913x_config.tuner_id_1;
-
- /* TODO we always use IT9137 possible references here*/
- /* Documentation suggests don't care */
- switch (tuner_id) {
- case 0x51:
- case 0x52:
- case 0x60:
- case 0x61:
- case 0x62:
- default:
- case 0x38:
- tuner_type = IT9137;
- }
+ memcpy(&st->it913x_config, &it913x_config,
+ sizeof(struct ite_config));
adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach,
- &adap->dev->i2c_adap, adap_addr, adf, tuner_type);
+ &adap->dev->i2c_adap, adap_addr, &st->it913x_config);
if (adap->id == 0 && adap->fe_adap[0].fe) {
ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1);
@@ -536,13 +772,13 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_LSB,
ep_size & 0xff);
ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8);
- ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, 0x80);
+ ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, pkt_size);
} else if (adap->id == 1 && adap->fe_adap[0].fe) {
ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x6f);
ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_LSB,
ep_size & 0xff);
ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8);
- ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, 0x80);
+ ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, pkt_size);
ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_EN, 0x1);
ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_SERIAL, 0x1);
ret = it913x_wr_reg(udev, DEV_1, TOP_HOSTB_SER_MODE, 0x1);
@@ -582,6 +818,9 @@ static int it913x_probe(struct usb_interface *intf,
static struct usb_device_id it913x_table[] = {
{ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) },
{ USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135) },
+ { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137) },
+ { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005) },
+ { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006) },
{} /* Terminating entry */
};
@@ -614,8 +853,8 @@ static struct dvb_usb_device_properties it913x_properties = {
.endpoint = 0x04,
.u = {/* Keep Low if PID filter on */
.bulk = {
- .buffersize = 3584,
-
+ .buffersize =
+ TS_BUFFER_SIZE_PID,
}
}
}
@@ -639,8 +878,8 @@ static struct dvb_usb_device_properties it913x_properties = {
.endpoint = 0x05,
.u = {
.bulk = {
- .buffersize = 3584,
-
+ .buffersize =
+ TS_BUFFER_SIZE_PID,
}
}
}
@@ -654,10 +893,10 @@ static struct dvb_usb_device_properties it913x_properties = {
.rc_query = it913x_rc_query,
.rc_interval = IT913X_POLL,
.allowed_protos = RC_TYPE_NEC,
- .rc_codes = RC_MAP_KWORLD_315U,
+ .rc_codes = RC_MAP_IT913X_V1,
},
.i2c_algo = &it913x_i2c_algo,
- .num_device_descs = 2,
+ .num_device_descs = 5,
.devices = {
{ "Kworld UB499-2T T09(IT9137)",
{ &it913x_table[0], NULL },
@@ -665,6 +904,15 @@ static struct dvb_usb_device_properties it913x_properties = {
{ "ITE 9135 Generic",
{ &it913x_table[1], NULL },
},
+ { "Sveon STV22 Dual DVB-T HDTV(IT9137)",
+ { &it913x_table[2], NULL },
+ },
+ { "ITE 9135(9005) Generic",
+ { &it913x_table[3], NULL },
+ },
+ { "ITE 9135(9006) Generic",
+ { &it913x_table[4], NULL },
+ },
}
};
@@ -679,5 +927,5 @@ module_usb_driver(it913x_driver);
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
MODULE_DESCRIPTION("it913x USB 2 Driver");
-MODULE_VERSION("1.07");
+MODULE_VERSION("1.28");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
index 1a876a65ed56..5dde06d066ff 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.c
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -77,6 +77,7 @@
#include "stv0299.h"
#include "dvb-pll.h"
#include "z0194a.h"
+#include "m88rs2000.h"
@@ -104,7 +105,7 @@ MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
static int pid_filter;
module_param_named(pid, pid_filter, int, 0644);
-MODULE_PARM_DESC(pid, "set default 0=on 1=off");
+MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -113,6 +114,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define TUNER_LG 0x1
#define TUNER_S7395 0x2
#define TUNER_S0194 0x3
+#define TUNER_RS2000 0x4
struct lme2510_state {
u8 id;
@@ -121,6 +123,8 @@ struct lme2510_state {
u8 signal_level;
u8 signal_sn;
u8 time_key;
+ u8 last_key;
+ u8 key_timeout;
u8 i2c_talk_onoff;
u8 i2c_gate;
u8 i2c_tuner_gate_w;
@@ -128,6 +132,7 @@ struct lme2510_state {
u8 i2c_tuner_addr;
u8 stream_on;
u8 pid_size;
+ u8 pid_off;
void *buffer;
struct urb *lme_urb;
void *usb_buffer;
@@ -178,14 +183,8 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
/* the read/write capped at 64 */
memcpy(buff, wbuf, (wlen < 64) ? wlen : 64);
- ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
-
ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
- msleep(10);
-
- ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01));
-
ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ?
rlen : 64 , 0x01);
@@ -199,9 +198,14 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
static int lme2510_stream_restart(struct dvb_usb_device *d)
{
- static u8 stream_on[] = LME_ST_ON_W;
+ struct lme2510_state *st = d->priv;
+ u8 all_pids[] = LME_ALL_PIDS;
+ u8 stream_on[] = LME_ST_ON_W;
int ret;
- u8 rbuff[10];
+ u8 rbuff[1];
+ if (st->pid_off)
+ ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids),
+ rbuff, sizeof(rbuff));
/*Restart Stream Command*/
ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on),
rbuff, sizeof(rbuff));
@@ -308,6 +312,14 @@ static void lme2510_int_response(struct urb *lme_urb)
((ibuf[2] & 0x01) << 0x03);
}
break;
+ case TUNER_RS2000:
+ if (ibuf[2] > 0)
+ st->signal_lock = 0xff;
+ else
+ st->signal_lock = 0xf0;
+ st->signal_level = ibuf[4];
+ st->signal_sn = ibuf[5];
+ st->time_key = ibuf[7];
default:
break;
}
@@ -359,19 +371,20 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct lme2510_state *st = adap->dev->priv;
- static u8 clear_pid_reg[] = LME_CLEAR_PID;
+ static u8 clear_pid_reg[] = LME_ALL_PIDS;
static u8 rbuf[1];
int ret;
deb_info(1, "PID Clearing Filter");
- ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
- if (ret < 0)
- return -EAGAIN;
+ mutex_lock(&adap->dev->i2c_mutex);
- if (!onoff)
+ if (!onoff) {
ret |= lme2510_usb_talk(adap->dev, clear_pid_reg,
sizeof(clear_pid_reg), rbuf, sizeof(rbuf));
+ st->pid_off = true;
+ } else
+ st->pid_off = false;
st->pid_size = 0;
@@ -388,13 +401,10 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__,
pid, index, onoff);
- if (onoff)
- if (!pid_filter) {
- ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
- if (ret < 0)
- return -EAGAIN;
- ret |= lme2510_enable_pid(adap->dev, index, pid);
- mutex_unlock(&adap->dev->i2c_mutex);
+ if (onoff) {
+ mutex_lock(&adap->dev->i2c_mutex);
+ ret |= lme2510_enable_pid(adap->dev, index, pid);
+ mutex_unlock(&adap->dev->i2c_mutex);
}
@@ -426,9 +436,6 @@ static int lme2510_msg(struct dvb_usb_device *d,
int ret = 0;
struct lme2510_state *st = d->priv;
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
-
if (st->i2c_talk_onoff == 1) {
ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
@@ -457,8 +464,6 @@ static int lme2510_msg(struct dvb_usb_device *d,
st->i2c_talk_onoff = 0;
}
}
- if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5))
- msleep(5);
}
break;
case TUNER_S0194:
@@ -473,10 +478,12 @@ static int lme2510_msg(struct dvb_usb_device *d,
}
}
break;
+ case TUNER_RS2000:
default:
break;
}
} else {
+ /* TODO rewrite this section */
switch (st->tuner_config) {
case TUNER_LG:
switch (wbuf[3]) {
@@ -560,6 +567,24 @@ static int lme2510_msg(struct dvb_usb_device *d,
break;
}
break;
+ case TUNER_RS2000:
+ switch (wbuf[3]) {
+ case 0x8c:
+ rbuf[0] = 0x55;
+ rbuf[1] = 0xff;
+ if (st->last_key == st->time_key) {
+ st->key_timeout++;
+ if (st->key_timeout > 5)
+ rbuf[1] = 0;
+ } else
+ st->key_timeout = 0;
+ st->last_key = st->time_key;
+ break;
+ default:
+ lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+ st->i2c_talk_onoff = 1;
+ break;
+ }
default:
break;
}
@@ -569,8 +594,6 @@ static int lme2510_msg(struct dvb_usb_device *d,
}
- mutex_unlock(&d->i2c_mutex);
-
return ret;
}
@@ -585,6 +608,8 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
u16 len;
u8 gate = st->i2c_gate;
+ mutex_lock(&d->i2c_mutex);
+
if (gate == 0)
gate = 5;
@@ -623,6 +648,7 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) {
deb_info(1, "i2c transfer failed.");
+ mutex_unlock(&d->i2c_mutex);
return -EAGAIN;
}
@@ -635,6 +661,8 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
}
}
}
+
+ mutex_unlock(&d->i2c_mutex);
return i;
}
@@ -654,6 +682,9 @@ static int lme2510_identify_state(struct usb_device *udev,
struct dvb_usb_device_description **desc,
int *cold)
{
+ if (pid_filter != 2)
+ props->adapter[0].fe[0].caps &=
+ ~DVB_USB_ADAP_NEED_PID_FILTERING;
*cold = 0;
return 0;
}
@@ -661,7 +692,7 @@ static int lme2510_identify_state(struct usb_device *udev,
static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct lme2510_state *st = adap->dev->priv;
- static u8 clear_reg_3[] = LME_CLEAR_PID;
+ static u8 clear_reg_3[] = LME_ALL_PIDS;
static u8 rbuf[1];
int ret = 0, rlen = sizeof(rbuf);
@@ -673,8 +704,7 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
else {
deb_info(1, "STM Steam Off");
/* mutex is here only to avoid collision with I2C */
- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
- return -EAGAIN;
+ mutex_lock(&adap->dev->i2c_mutex);
ret = lme2510_usb_talk(adap->dev, clear_reg_3,
sizeof(clear_reg_3), rbuf, rlen);
@@ -779,16 +809,18 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw";
const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw";
+ const char fw_c_rs2000[] = "dvb-usb-lme2510c-rs2000.fw";
const char fw_lg[] = "dvb-usb-lme2510-lg.fw";
const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw";
const char *fw_lme;
- int ret, cold_fw;
+ int ret = 0, cold_fw;
cold = (cold > 0) ? (cold & 1) : 0;
cold_fw = !cold;
- if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) {
+ switch (le16_to_cpu(udev->descriptor.idProduct)) {
+ case 0x1122:
switch (dvb_usb_lme2510_firmware) {
default:
dvb_usb_lme2510_firmware = TUNER_S0194;
@@ -811,7 +843,8 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
cold_fw = 0;
break;
}
- } else {
+ break;
+ case 0x1120:
switch (dvb_usb_lme2510_firmware) {
default:
dvb_usb_lme2510_firmware = TUNER_S7395;
@@ -840,8 +873,17 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
cold_fw = 0;
break;
}
+ break;
+ case 0x22f0:
+ fw_lme = fw_c_rs2000;
+ ret = request_firmware(&fw, fw_lme, &udev->dev);
+ dvb_usb_lme2510_firmware = TUNER_RS2000;
+ break;
+ default:
+ fw_lme = fw_c_s7395;
}
+
if (cold_fw) {
info("FRM Loading %s file", fw_lme);
ret = lme2510_download_firmware(udev, fw);
@@ -904,6 +946,29 @@ static struct stv0299_config sharp_z0194_config = {
.set_symbol_rate = sharp_z0194a_set_symbol_rate,
};
+static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe,
+ int caller)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dvb_usb_device *d = adap->dev;
+ struct lme2510_state *st = d->priv;
+
+ mutex_lock(&d->i2c_mutex);
+ if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) {
+ st->i2c_talk_onoff = 0;
+ lme2510_stream_restart(d);
+ }
+ mutex_unlock(&d->i2c_mutex);
+
+ return 0;
+}
+
+static struct m88rs2000_config m88rs2000_config = {
+ .demod_addr = 0xd0,
+ .tuner_addr = 0xc0,
+ .set_ts_params = dm04_rs2000_set_ts_param,
+};
+
static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
fe_sec_voltage_t voltage)
{
@@ -913,8 +978,7 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
static u8 rbuf[1];
int ret = 0, len = 3, rlen = 1;
- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
- return -EAGAIN;
+ mutex_lock(&adap->dev->i2c_mutex);
switch (voltage) {
case SEC_VOLTAGE_18:
@@ -935,12 +999,31 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
return (ret < 0) ? -ENODEV : 0;
}
+static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct lme2510_state *st = adap->dev->priv;
+
+ *strength = (u16)((u32)st->signal_level * 0xffff / 0x7f);
+ return 0;
+}
+
+static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct lme2510_state *st = adap->dev->priv;
+
+ *snr = (u16)((u32)st->signal_sn * 0xffff / 0xff);
+ return 0;
+}
+
static int lme_name(struct dvb_usb_adapter *adap)
{
struct lme2510_state *st = adap->dev->priv;
const char *desc = adap->dev->desc->name;
char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
- " SHARP:BS2F7HZ0194"};
+ " SHARP:BS2F7HZ0194", " RS2000"};
char *name = adap->fe_adap[0].fe->ops.info.name;
strlcpy(name, desc, 128);
@@ -956,60 +1039,82 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
int ret = 0;
st->i2c_talk_onoff = 1;
+ switch (le16_to_cpu(adap->dev->udev->descriptor.idProduct)) {
+ case 0x1122:
+ case 0x1120:
+ st->i2c_gate = 4;
+ adap->fe_adap[0].fe = dvb_attach(tda10086_attach,
+ &tda10086_config, &adap->dev->i2c_adap);
+ if (adap->fe_adap[0].fe) {
+ info("TUN Found Frontend TDA10086");
+ st->i2c_tuner_gate_w = 4;
+ st->i2c_tuner_gate_r = 4;
+ st->i2c_tuner_addr = 0xc0;
+ st->tuner_config = TUNER_LG;
+ if (dvb_usb_lme2510_firmware != TUNER_LG) {
+ dvb_usb_lme2510_firmware = TUNER_LG;
+ ret = lme_firmware_switch(adap->dev->udev, 1);
+ }
+ break;
+ }
- st->i2c_gate = 4;
- adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config,
- &adap->dev->i2c_adap);
-
- if (adap->fe_adap[0].fe) {
- info("TUN Found Frontend TDA10086");
- st->i2c_tuner_gate_w = 4;
- st->i2c_tuner_gate_r = 4;
- st->i2c_tuner_addr = 0xc0;
- st->tuner_config = TUNER_LG;
- if (dvb_usb_lme2510_firmware != TUNER_LG) {
- dvb_usb_lme2510_firmware = TUNER_LG;
- ret = lme_firmware_switch(adap->dev->udev, 1);
+ st->i2c_gate = 4;
+ adap->fe_adap[0].fe = dvb_attach(stv0299_attach,
+ &sharp_z0194_config, &adap->dev->i2c_adap);
+ if (adap->fe_adap[0].fe) {
+ info("FE Found Stv0299");
+ st->i2c_tuner_gate_w = 4;
+ st->i2c_tuner_gate_r = 5;
+ st->i2c_tuner_addr = 0xc0;
+ st->tuner_config = TUNER_S0194;
+ if (dvb_usb_lme2510_firmware != TUNER_S0194) {
+ dvb_usb_lme2510_firmware = TUNER_S0194;
+ ret = lme_firmware_switch(adap->dev->udev, 1);
+ }
+ break;
}
- goto end;
- }
- st->i2c_gate = 4;
- adap->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194_config,
+ st->i2c_gate = 5;
+ adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config,
&adap->dev->i2c_adap);
- if (adap->fe_adap[0].fe) {
- info("FE Found Stv0299");
- st->i2c_tuner_gate_w = 4;
- st->i2c_tuner_gate_r = 5;
- st->i2c_tuner_addr = 0xc0;
- st->tuner_config = TUNER_S0194;
- if (dvb_usb_lme2510_firmware != TUNER_S0194) {
- dvb_usb_lme2510_firmware = TUNER_S0194;
- ret = lme_firmware_switch(adap->dev->udev, 1);
+
+ if (adap->fe_adap[0].fe) {
+ info("FE Found Stv0288");
+ st->i2c_tuner_gate_w = 4;
+ st->i2c_tuner_gate_r = 5;
+ st->i2c_tuner_addr = 0xc0;
+ st->tuner_config = TUNER_S7395;
+ if (dvb_usb_lme2510_firmware != TUNER_S7395) {
+ dvb_usb_lme2510_firmware = TUNER_S7395;
+ ret = lme_firmware_switch(adap->dev->udev, 1);
+ }
+ break;
}
- goto end;
- }
+ case 0x22f0:
+ st->i2c_gate = 5;
+ adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach,
+ &m88rs2000_config, &adap->dev->i2c_adap);
- st->i2c_gate = 5;
- adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config,
- &adap->dev->i2c_adap);
- if (adap->fe_adap[0].fe) {
- info("FE Found Stv0288");
- st->i2c_tuner_gate_w = 4;
- st->i2c_tuner_gate_r = 5;
- st->i2c_tuner_addr = 0xc0;
- st->tuner_config = TUNER_S7395;
- if (dvb_usb_lme2510_firmware != TUNER_S7395) {
- dvb_usb_lme2510_firmware = TUNER_S7395;
- ret = lme_firmware_switch(adap->dev->udev, 1);
+ if (adap->fe_adap[0].fe) {
+ info("FE Found M88RS2000");
+ st->i2c_tuner_gate_w = 5;
+ st->i2c_tuner_gate_r = 5;
+ st->i2c_tuner_addr = 0xc0;
+ st->tuner_config = TUNER_RS2000;
+ adap->fe_adap[0].fe->ops.read_signal_strength =
+ dm04_rs2000_read_signal_strength;
+ adap->fe_adap[0].fe->ops.read_snr =
+ dm04_rs2000_read_snr;
}
- } else {
- info("DM04 Not Supported");
- return -ENODEV;
+ break;
}
+ if (adap->fe_adap[0].fe == NULL) {
+ info("DM04/QQBOX Not Powered up or not Supported");
+ return -ENODEV;
+ }
-end: if (ret) {
+ if (ret) {
if (adap->fe_adap[0].fe) {
dvb_frontend_detach(adap->fe_adap[0].fe);
adap->fe_adap[0].fe = NULL;
@@ -1026,7 +1131,7 @@ end: if (ret) {
static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
{
struct lme2510_state *st = adap->dev->priv;
- char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA"};
+ char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"};
int ret = 0;
switch (st->tuner_config) {
@@ -1045,6 +1150,9 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
&adap->dev->i2c_adap, DVB_PLL_OPERA1))
ret = st->tuner_config;
break;
+ case TUNER_RS2000:
+ ret = st->tuner_config;
+ break;
default:
break;
}
@@ -1052,7 +1160,7 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
if (ret)
info("TUN Found %s tuner", tun_msg[ret]);
else {
- info("TUN No tuner found --- reseting device");
+ info("TUN No tuner found --- resetting device");
lme_coldreset(adap->dev->udev);
return -ENODEV;
}
@@ -1073,10 +1181,9 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
static u8 lnb_on[] = LNB_ON;
static u8 lnb_off[] = LNB_OFF;
static u8 rbuf[1];
- int ret, len = 3, rlen = 1;
+ int ret = 0, len = 3, rlen = 1;
- if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
+ mutex_lock(&d->i2c_mutex);
if (onoff)
ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
@@ -1134,6 +1241,7 @@ static int lme2510_probe(struct usb_interface *intf,
static struct usb_device_id lme2510_table[] = {
{ USB_DEVICE(0x3344, 0x1122) }, /* LME2510 */
{ USB_DEVICE(0x3344, 0x1120) }, /* LME2510C */
+ { USB_DEVICE(0x3344, 0x22f0) }, /* LME2510C RS2000 */
{} /* Terminating entry */
};
@@ -1151,7 +1259,7 @@ static struct dvb_usb_device_properties lme2510_properties = {
DVB_USB_ADAP_NEED_PID_FILTERING|
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.streaming_ctrl = lme2510_streaming_ctrl,
- .pid_filter_count = 15,
+ .pid_filter_count = 32,
.pid_filter = lme2510_pid_filter,
.pid_filter_ctrl = lme2510_pid_filter_ctrl,
.frontend_attach = dm04_lme2510_frontend_attach,
@@ -1202,7 +1310,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
DVB_USB_ADAP_NEED_PID_FILTERING|
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.streaming_ctrl = lme2510_streaming_ctrl,
- .pid_filter_count = 15,
+ .pid_filter_count = 32,
.pid_filter = lme2510_pid_filter,
.pid_filter_ctrl = lme2510_pid_filter_ctrl,
.frontend_attach = dm04_lme2510_frontend_attach,
@@ -1232,11 +1340,14 @@ static struct dvb_usb_device_properties lme2510c_properties = {
.identify_state = lme2510_identify_state,
.i2c_algo = &lme2510_i2c_algo,
.generic_bulk_ctrl_endpoint = 0,
- .num_device_descs = 1,
+ .num_device_descs = 2,
.devices = {
{ "DM04_LME2510C_DVB-S",
{ &lme2510_table[1], NULL },
},
+ { "DM04_LME2510C_DVB-S RS2000",
+ { &lme2510_table[2], NULL },
+ },
}
};
@@ -1293,5 +1404,5 @@ module_usb_driver(lme2510_driver);
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.90");
+MODULE_VERSION("1.99");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/dvb/dvb-usb/lmedm04.h
index ab21e2ef53fa..e9c207205c2f 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.h
+++ b/drivers/media/dvb/dvb-usb/lmedm04.h
@@ -41,6 +41,7 @@
#define LME_ST_ON_W {0x06, 0x00}
#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0}
#define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c}
+#define LME_ALL_PIDS {0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81}
/* LNB Voltage
* 07 XX XX
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c
index d1f58371c711..d83df4bb72d3 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c
+++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c
@@ -102,8 +102,8 @@ fail:
}
static
-int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state,
- fe_modulation_t *constellation)
+int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state,
+ fe_modulation_t *modulation)
{
u8 val;
int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val);
@@ -113,13 +113,13 @@ int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state,
switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) {
case 0:
- *constellation = QPSK;
+ *modulation = QPSK;
break;
case 1:
- *constellation = QAM_16;
+ *modulation = QAM_16;
break;
case 2:
- *constellation = QAM_64;
+ *modulation = QAM_64;
break;
}
fail:
@@ -284,8 +284,7 @@ static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state)
/* ------------------------------------------------------------------------ */
-static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe)
{
struct mxl111sf_demod_state *state = fe->demodulator_priv;
int ret = 0;
@@ -303,7 +302,7 @@ static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe,
mxl_dbg("()");
if (fe->ops.tuner_ops.set_params) {
- ret = fe->ops.tuner_ops.set_params(fe, param);
+ ret = fe->ops.tuner_ops.set_params(fe);
if (mxl_fail(ret))
goto fail;
msleep(50);
@@ -481,13 +480,13 @@ static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
struct mxl111sf_demod_state *state = fe->demodulator_priv;
- fe_modulation_t constellation;
+ fe_modulation_t modulation;
u16 snr;
mxl111sf_demod_calc_snr(state, &snr);
- mxl1x1sf_demod_get_tps_constellation(state, &constellation);
+ mxl1x1sf_demod_get_tps_modulation(state, &modulation);
- switch (constellation) {
+ switch (modulation) {
case QPSK:
*signal_strength = (snr >= 1300) ?
min(65535, snr * 44) : snr * 38;
@@ -508,9 +507,9 @@ static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe,
return 0;
}
-static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mxl111sf_demod_state *state = fe->demodulator_priv;
mxl_dbg("()");
@@ -518,18 +517,18 @@ static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe,
p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF;
#endif
if (fe->ops.tuner_ops.get_bandwidth)
- fe->ops.tuner_ops.get_bandwidth(fe, &p->u.ofdm.bandwidth);
+ fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz);
if (fe->ops.tuner_ops.get_frequency)
fe->ops.tuner_ops.get_frequency(fe, &p->frequency);
- mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_HP);
- mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_LP);
- mxl1x1sf_demod_get_tps_constellation(state, &p->u.ofdm.constellation);
+ mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP);
+ mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP);
+ mxl1x1sf_demod_get_tps_modulation(state, &p->modulation);
mxl1x1sf_demod_get_tps_guard_fft_mode(state,
- &p->u.ofdm.transmission_mode);
+ &p->transmission_mode);
mxl1x1sf_demod_get_tps_guard_interval(state,
- &p->u.ofdm.guard_interval);
+ &p->guard_interval);
mxl1x1sf_demod_get_tps_hierarchy(state,
- &p->u.ofdm.hierarchy_information);
+ &p->hierarchy);
return 0;
}
@@ -551,10 +550,9 @@ static void mxl111sf_demod_release(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops mxl111sf_demod_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "MaxLinear MxL111SF DVB-T demodulator",
- .type = FE_OFDM,
.frequency_min = 177000000,
.frequency_max = 858000000,
.frequency_stepsize = 166666,
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
index a6341058c4e7..72db6eef4b9c 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
+++ b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
@@ -38,6 +38,8 @@ struct mxl111sf_tuner_state {
struct mxl111sf_tuner_config *cfg;
+ enum mxl_if_freq if_freq;
+
u32 frequency;
u32 bandwidth;
};
@@ -186,7 +188,10 @@ static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
ctrl = iffcw & 0x00ff;
#endif
ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
- mxl_fail(ret);
+ if (mxl_fail(ret))
+ goto fail;
+
+ state->if_freq = state->cfg->if_freq;
fail:
return ret;
}
@@ -267,55 +272,49 @@ static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
/* ------------------------------------------------------------------------ */
-static int mxl111sf_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int mxl111sf_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
struct mxl111sf_tuner_state *state = fe->tuner_priv;
int ret;
u8 bw;
mxl_dbg("()");
- if (fe->ops.info.type == FE_ATSC) {
- switch (params->u.vsb.modulation) {
- case VSB_8:
- case VSB_16:
- bw = 0; /* ATSC */
- break;
- case QAM_64:
- case QAM_256:
- bw = 1; /* US CABLE */
- break;
- default:
- err("%s: modulation not set!", __func__);
- return -EINVAL;
- }
- } else if (fe->ops.info.type == FE_OFDM) {
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (delsys) {
+ case SYS_ATSC:
+ bw = 0; /* ATSC */
+ break;
+ case SYS_DVBC_ANNEX_B:
+ bw = 1; /* US CABLE */
+ break;
+ case SYS_DVBT:
+ switch (c->bandwidth_hz) {
+ case 6000000:
bw = 6;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
bw = 7;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
bw = 8;
break;
default:
err("%s: bandwidth not set!", __func__);
return -EINVAL;
}
- } else {
+ break;
+ default:
err("%s: modulation type not supported!", __func__);
return -EINVAL;
}
- ret = mxl1x1sf_tune_rf(fe, params->frequency, bw);
+ ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
if (mxl_fail(ret))
goto fail;
- state->frequency = params->frequency;
- state->bandwidth = (fe->ops.info.type == FE_OFDM) ?
- params->u.ofdm.bandwidth : 0;
+ state->frequency = c->frequency;
+ state->bandwidth = c->bandwidth_hz;
fail:
return ret;
}
@@ -407,6 +406,54 @@ static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
return 0;
}
+static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe,
+ u32 *frequency)
+{
+ struct mxl111sf_tuner_state *state = fe->tuner_priv;
+
+ *frequency = 0;
+
+ switch (state->if_freq) {
+ case MXL_IF_4_0: /* 4.0 MHz */
+ *frequency = 4000000;
+ break;
+ case MXL_IF_4_5: /* 4.5 MHz */
+ *frequency = 4500000;
+ break;
+ case MXL_IF_4_57: /* 4.57 MHz */
+ *frequency = 4570000;
+ break;
+ case MXL_IF_5_0: /* 5.0 MHz */
+ *frequency = 5000000;
+ break;
+ case MXL_IF_5_38: /* 5.38 MHz */
+ *frequency = 5380000;
+ break;
+ case MXL_IF_6_0: /* 6.0 MHz */
+ *frequency = 6000000;
+ break;
+ case MXL_IF_6_28: /* 6.28 MHz */
+ *frequency = 6280000;
+ break;
+ case MXL_IF_7_2: /* 7.2 MHz */
+ *frequency = 7200000;
+ break;
+ case MXL_IF_35_25: /* 35.25 MHz */
+ *frequency = 35250000;
+ break;
+ case MXL_IF_36: /* 36 MHz */
+ *frequency = 36000000;
+ break;
+ case MXL_IF_36_15: /* 36.15 MHz */
+ *frequency = 36150000;
+ break;
+ case MXL_IF_44: /* 44 MHz */
+ *frequency = 44000000;
+ break;
+ }
+ return 0;
+}
+
static int mxl111sf_tuner_release(struct dvb_frontend *fe)
{
struct mxl111sf_tuner_state *state = fe->tuner_priv;
@@ -436,6 +483,7 @@ static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
.get_rf_strength = mxl111sf_get_rf_strength,
.get_frequency = mxl111sf_tuner_get_frequency,
.get_bandwidth = mxl111sf_tuner_get_bandwidth,
+ .get_if_frequency = mxl111sf_tuner_get_if_frequency,
.release = mxl111sf_tuner_release,
};
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c
index 825a8b242e09..81305de2fea5 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf.c
+++ b/drivers/media/dvb/dvb-usb/mxl111sf.c
@@ -351,15 +351,13 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
adap_state->ep6_clockphase,
0, 0);
mxl_fail(ret);
+#if 0
} else {
ret = mxl111sf_disable_656_port(state);
mxl_fail(ret);
+#endif
}
- mxl111sf_read_reg(state, 0x12, &tmp);
- tmp &= ~0x04;
- mxl111sf_write_reg(state, 0x12, tmp);
-
return ret;
}
@@ -758,6 +756,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table);
#define MXL111SF_EP4_BULK_STREAMING_CONFIG \
+ .size_of_priv = sizeof(struct mxl111sf_adap_state), \
.streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \
.stream = { \
.type = USB_BULK, \
@@ -772,6 +771,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table);
/* FIXME: works for v6 but not v8 silicon */
#define MXL111SF_EP4_ISOC_STREAMING_CONFIG \
+ .size_of_priv = sizeof(struct mxl111sf_adap_state), \
.streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \
.stream = { \
.type = USB_ISOC, \
@@ -788,6 +788,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table);
}
#define MXL111SF_EP6_BULK_STREAMING_CONFIG \
+ .size_of_priv = sizeof(struct mxl111sf_adap_state), \
.streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \
.stream = { \
.type = USB_BULK, \
@@ -802,6 +803,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table);
/* FIXME */
#define MXL111SF_EP6_ISOC_STREAMING_CONFIG \
+ .size_of_priv = sizeof(struct mxl111sf_adap_state), \
.streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \
.stream = { \
.type = USB_ISOC, \
@@ -839,8 +841,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = {
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
.num_frontends = 1,
.fe = {{
- .size_of_priv = sizeof(struct mxl111sf_adap_state),
-
.frontend_attach = mxl111sf_attach_demod,
.tuner_attach = mxl111sf_attach_tuner,
@@ -883,8 +883,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = {
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
.num_frontends = 1,
.fe = {{
- .size_of_priv = sizeof(struct mxl111sf_adap_state),
-
.frontend_attach = mxl111sf_attach_demod,
.tuner_attach = mxl111sf_attach_tuner,
@@ -927,16 +925,12 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
.num_frontends = 2,
.fe = {{
- .size_of_priv = sizeof(struct mxl111sf_adap_state),
-
.frontend_attach = mxl111sf_lgdt3305_frontend_attach,
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP6_BULK_STREAMING_CONFIG,
},
{
- .size_of_priv = sizeof(struct mxl111sf_adap_state),
-
.frontend_attach = mxl111sf_attach_demod,
.tuner_attach = mxl111sf_attach_tuner,
@@ -992,16 +986,12 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
.num_frontends = 2,
.fe = {{
- .size_of_priv = sizeof(struct mxl111sf_adap_state),
-
.frontend_attach = mxl111sf_lgdt3305_frontend_attach,
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP6_ISOC_STREAMING_CONFIG,
},
{
- .size_of_priv = sizeof(struct mxl111sf_adap_state),
-
.frontend_attach = mxl111sf_attach_demod,
.tuner_attach = mxl111sf_attach_tuner,
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
new file mode 100644
index 000000000000..8f4736a10fc8
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
@@ -0,0 +1,982 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "rtl28xxu.h"
+
+#include "rtl2830.h"
+
+#include "qt1010.h"
+#include "mt2060.h"
+#include "mxl5005s.h"
+
+/* debug */
+static int dvb_usb_rtl28xxu_debug;
+module_param_named(debug, dvb_usb_rtl28xxu_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
+{
+ int ret;
+ unsigned int pipe;
+ u8 requesttype;
+ u8 *buf;
+
+ buf = kmalloc(req->size, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (req->index & CMD_WR_FLAG) {
+ /* write */
+ memcpy(buf, req->data, req->size);
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+ pipe = usb_sndctrlpipe(d->udev, 0);
+ } else {
+ /* read */
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+ pipe = usb_rcvctrlpipe(d->udev, 0);
+ }
+
+ ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value,
+ req->index, buf, req->size, 1000);
+ if (ret > 0)
+ ret = 0;
+
+ deb_dump(0, requesttype, req->value, req->index, buf, req->size,
+ deb_xfer);
+
+ /* read request, copy returned data to return buf */
+ if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
+ memcpy(req->data, buf, req->size);
+
+ kfree(buf);
+
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ deb_info("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl2831_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+{
+ struct rtl28xxu_req req;
+
+ if (reg < 0x3000)
+ req.index = CMD_USB_WR;
+ else if (reg < 0x4000)
+ req.index = CMD_SYS_WR;
+ else
+ req.index = CMD_IR_WR;
+
+ req.value = reg;
+ req.size = len;
+ req.data = val;
+
+ return rtl28xxu_ctrl_msg(d, &req);
+}
+
+static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+{
+ struct rtl28xxu_req req;
+
+ if (reg < 0x3000)
+ req.index = CMD_USB_RD;
+ else if (reg < 0x4000)
+ req.index = CMD_SYS_RD;
+ else
+ req.index = CMD_IR_RD;
+
+ req.value = reg;
+ req.size = len;
+ req.data = val;
+
+ return rtl28xxu_ctrl_msg(d, &req);
+}
+
+static int rtl2831_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+{
+ return rtl2831_wr_regs(d, reg, &val, 1);
+}
+
+static int rtl2831_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+{
+ return rtl2831_rd_regs(d, reg, val, 1);
+}
+
+/* I2C */
+static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ int ret;
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct rtl28xxu_priv *priv = d->priv;
+ struct rtl28xxu_req req;
+
+ /*
+ * It is not known which are real I2C bus xfer limits, but testing
+ * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes.
+ * TODO: find out RTL2832U lens
+ */
+
+ /*
+ * I2C adapter logic looks rather complicated due to fact it handles
+ * three different access methods. Those methods are;
+ * 1) integrated demod access
+ * 2) old I2C access
+ * 3) new I2C access
+ *
+ * Used method is selected in order 1, 2, 3. Method 3 can handle all
+ * requests but there is two reasons why not use it always;
+ * 1) It is most expensive, usually two USB messages are needed
+ * 2) At least RTL2831U does not support it
+ *
+ * Method 3 is needed in case of I2C write+read (typical register read)
+ * where write is more than one byte.
+ */
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
+ (msg[1].flags & I2C_M_RD)) {
+ if (msg[0].len > 24 || msg[1].len > 24) {
+ /* TODO: check msg[0].len max */
+ ret = -EOPNOTSUPP;
+ goto err_mutex_unlock;
+ } else if (msg[0].addr == 0x10) {
+ /* method 1 - integrated demod */
+ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+ req.index = CMD_DEMOD_RD | priv->page;
+ req.size = msg[1].len;
+ req.data = &msg[1].buf[0];
+ ret = rtl28xxu_ctrl_msg(d, &req);
+ } else if (msg[0].len < 2) {
+ /* method 2 - old I2C */
+ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+ req.index = CMD_I2C_RD;
+ req.size = msg[1].len;
+ req.data = &msg[1].buf[0];
+ ret = rtl28xxu_ctrl_msg(d, &req);
+ } else {
+ /* method 3 - new I2C */
+ req.value = (msg[0].addr << 1);
+ req.index = CMD_I2C_DA_WR;
+ req.size = msg[0].len;
+ req.data = msg[0].buf;
+ ret = rtl28xxu_ctrl_msg(d, &req);
+ if (ret)
+ goto err_mutex_unlock;
+
+ req.value = (msg[0].addr << 1);
+ req.index = CMD_I2C_DA_RD;
+ req.size = msg[1].len;
+ req.data = msg[1].buf;
+ ret = rtl28xxu_ctrl_msg(d, &req);
+ }
+ } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+ if (msg[0].len > 22) {
+ /* TODO: check msg[0].len max */
+ ret = -EOPNOTSUPP;
+ goto err_mutex_unlock;
+ } else if (msg[0].addr == 0x10) {
+ /* method 1 - integrated demod */
+ if (msg[0].buf[0] == 0x00) {
+ /* save demod page for later demod access */
+ priv->page = msg[0].buf[1];
+ ret = 0;
+ } else {
+ req.value = (msg[0].buf[0] << 8) |
+ (msg[0].addr << 1);
+ req.index = CMD_DEMOD_WR | priv->page;
+ req.size = msg[0].len-1;
+ req.data = &msg[0].buf[1];
+ ret = rtl28xxu_ctrl_msg(d, &req);
+ }
+ } else if (msg[0].len < 23) {
+ /* method 2 - old I2C */
+ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+ req.index = CMD_I2C_WR;
+ req.size = msg[0].len-1;
+ req.data = &msg[0].buf[1];
+ ret = rtl28xxu_ctrl_msg(d, &req);
+ } else {
+ /* method 3 - new I2C */
+ req.value = (msg[0].addr << 1);
+ req.index = CMD_I2C_DA_WR;
+ req.size = msg[0].len;
+ req.data = msg[0].buf;
+ ret = rtl28xxu_ctrl_msg(d, &req);
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+err_mutex_unlock:
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret ? ret : num;
+}
+
+static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm rtl28xxu_i2c_algo = {
+ .master_xfer = rtl28xxu_i2c_xfer,
+ .functionality = rtl28xxu_i2c_func,
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
+ .i2c_addr = 0x10, /* 0x20 */
+ .xtal = 28800000,
+ .ts_mode = 0,
+ .spec_inv = 1,
+ .if_dvbt = 36150000,
+ .vtop = 0x20,
+ .krf = 0x04,
+ .agc_targ_val = 0x2d,
+
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
+ .i2c_addr = 0x10, /* 0x20 */
+ .xtal = 28800000,
+ .ts_mode = 0,
+ .spec_inv = 1,
+ .if_dvbt = 36125000,
+ .vtop = 0x20,
+ .krf = 0x04,
+ .agc_targ_val = 0x2d,
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
+ .i2c_addr = 0x10, /* 0x20 */
+ .xtal = 28800000,
+ .ts_mode = 0,
+ .spec_inv = 0,
+ .if_dvbt = 4570000,
+ .vtop = 0x3f,
+ .krf = 0x04,
+ .agc_targ_val = 0x3e,
+};
+
+static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ struct rtl28xxu_priv *priv = adap->dev->priv;
+ u8 buf[1];
+ struct rtl2830_config *rtl2830_config;
+ /* open RTL2831U/RTL2830 I2C gate */
+ struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" };
+ /* for MT2060 tuner probe */
+ struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf };
+ /* for QT1010 tuner probe */
+ struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };
+
+ deb_info("%s:\n", __func__);
+
+ /*
+ * RTL2831U GPIOs
+ * =========================================================
+ * GPIO0 | tuner#0 | 0 off | 1 on | MXL5005S (?)
+ * GPIO2 | LED | 0 off | 1 on |
+ * GPIO4 | tuner#1 | 0 on | 1 off | MT2060
+ */
+
+ /* GPIO direction */
+ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
+ if (ret)
+ goto err;
+
+ /* enable as output GPIO0, GPIO2, GPIO4 */
+ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
+ if (ret)
+ goto err;
+
+ /*
+ * Probe used tuner. We need to know used tuner before demod attach
+ * since there is some demod params needed to set according to tuner.
+ */
+
+ /* open demod I2C gate */
+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
+ if (ret)
+ goto err;
+
+ /* check QT1010 ID(?) register; reg=0f val=2c */
+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_qt1010);
+ if (ret == 0 && buf[0] == 0x2c) {
+ priv->tuner = TUNER_RTL2830_QT1010;
+ rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
+ deb_info("%s: QT1010\n", __func__);
+ goto found;
+ } else {
+ deb_info("%s: QT1010 probe failed=%d - %02x\n",
+ __func__, ret, buf[0]);
+ }
+
+ /* open demod I2C gate */
+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
+ if (ret)
+ goto err;
+
+ /* check MT2060 ID register; reg=00 val=63 */
+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2060);
+ if (ret == 0 && buf[0] == 0x63) {
+ priv->tuner = TUNER_RTL2830_MT2060;
+ rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
+ deb_info("%s: MT2060\n", __func__);
+ goto found;
+ } else {
+ deb_info("%s: MT2060 probe failed=%d - %02x\n",
+ __func__, ret, buf[0]);
+ }
+
+ /* assume MXL5005S */
+ ret = 0;
+ priv->tuner = TUNER_RTL2830_MXL5005S;
+ rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
+ deb_info("%s: MXL5005S\n", __func__);
+ goto found;
+
+found:
+ /* attach demodulator */
+ adap->fe_adap[0].fe = dvb_attach(rtl2830_attach, rtl2830_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe_adap[0].fe == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ return ret;
+err:
+ deb_info("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ struct rtl28xxu_priv *priv = adap->dev->priv;
+ u8 buf[1];
+ /* open RTL2832U/RTL2832 I2C gate */
+ struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
+ /* close RTL2832U/RTL2832 I2C gate */
+ struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
+ /* for FC2580 tuner probe */
+ struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
+
+ deb_info("%s:\n", __func__);
+
+ /* GPIO direction */
+ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
+ if (ret)
+ goto err;
+
+ /* enable as output GPIO0, GPIO2, GPIO4 */
+ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
+ if (ret)
+ goto err;
+
+ ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8);
+ if (ret)
+ goto err;
+
+ /*
+ * Probe used tuner. We need to know used tuner before demod attach
+ * since there is some demod params needed to set according to tuner.
+ */
+
+ /* open demod I2C gate */
+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_open);
+ if (ret)
+ goto err;
+
+ /* check FC2580 ID register; reg=01 val=56 */
+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
+ if (ret == 0 && buf[0] == 0x56) {
+ priv->tuner = TUNER_RTL2832_FC2580;
+ deb_info("%s: FC2580\n", __func__);
+ goto found;
+ } else {
+ deb_info("%s: FC2580 probe failed=%d - %02x\n",
+ __func__, ret, buf[0]);
+ }
+
+ /* close demod I2C gate */
+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
+ if (ret)
+ goto err;
+
+ /* tuner not found */
+ ret = -ENODEV;
+ goto err;
+
+found:
+ /* close demod I2C gate */
+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
+ if (ret)
+ goto err;
+
+ /* attach demodulator */
+ /* TODO: */
+
+ return ret;
+err:
+ deb_info("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static struct qt1010_config rtl28xxu_qt1010_config = {
+ .i2c_address = 0x62, /* 0xc4 */
+};
+
+static struct mt2060_config rtl28xxu_mt2060_config = {
+ .i2c_address = 0x60, /* 0xc0 */
+ .clock_out = 0,
+};
+
+static struct mxl5005s_config rtl28xxu_mxl5005s_config = {
+ .i2c_address = 0x63, /* 0xc6 */
+ .if_freq = IF_FREQ_4570000HZ,
+ .xtal_freq = CRYSTAL_FREQ_16000000HZ,
+ .agc_mode = MXL_SINGLE_AGC,
+ .tracking_filter = MXL_TF_C_H,
+ .rssi_enable = MXL_RSSI_ENABLE,
+ .cap_select = MXL_CAP_SEL_ENABLE,
+ .div_out = MXL_DIV_OUT_4,
+ .clock_out = MXL_CLOCK_OUT_DISABLE,
+ .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+ .top = MXL5005S_TOP_25P2,
+ .mod_mode = MXL_DIGITAL_MODE,
+ .if_mode = MXL_ZERO_IF,
+ .AgcMasterByte = 0x00,
+};
+
+static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ struct rtl28xxu_priv *priv = adap->dev->priv;
+ struct i2c_adapter *rtl2830_tuner_i2c;
+ struct dvb_frontend *fe;
+
+ deb_info("%s:\n", __func__);
+
+ /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
+ rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe);
+
+ switch (priv->tuner) {
+ case TUNER_RTL2830_QT1010:
+ fe = dvb_attach(qt1010_attach, adap->fe_adap[0].fe,
+ rtl2830_tuner_i2c, &rtl28xxu_qt1010_config);
+ break;
+ case TUNER_RTL2830_MT2060:
+ fe = dvb_attach(mt2060_attach, adap->fe_adap[0].fe,
+ rtl2830_tuner_i2c, &rtl28xxu_mt2060_config,
+ 1220);
+ break;
+ case TUNER_RTL2830_MXL5005S:
+ fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
+ rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config);
+ break;
+ default:
+ fe = NULL;
+ err("unknown tuner=%d", priv->tuner);
+ }
+
+ if (fe == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ return 0;
+err:
+ deb_info("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ struct rtl28xxu_priv *priv = adap->dev->priv;
+ struct dvb_frontend *fe;
+
+ deb_info("%s:\n", __func__);
+
+ switch (priv->tuner) {
+ case TUNER_RTL2832_FC2580:
+ /* TODO: */
+ fe = NULL;
+ break;
+ default:
+ fe = NULL;
+ err("unknown tuner=%d", priv->tuner);
+ }
+
+ if (fe == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ return 0;
+err:
+ deb_info("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
+{
+ int ret;
+ u8 buf[2], gpio;
+
+ deb_info("%s: onoff=%d\n", __func__, onoff);
+
+ ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
+ if (ret)
+ goto err;
+
+ if (onoff) {
+ buf[0] = 0x00;
+ buf[1] = 0x00;
+ gpio |= 0x04; /* LED on */
+ } else {
+ buf[0] = 0x10; /* stall EPA */
+ buf[1] = 0x02; /* reset EPA */
+ gpio &= (~0x04); /* LED off */
+ }
+
+ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio);
+ if (ret)
+ goto err;
+
+ ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ deb_info("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ int ret;
+ u8 gpio, sys0;
+
+ deb_info("%s: onoff=%d\n", __func__, onoff);
+
+ /* demod adc */
+ ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0);
+ if (ret)
+ goto err;
+
+ /* tuner power, read GPIOs */
+ ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
+ if (ret)
+ goto err;
+
+ deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
+
+ if (onoff) {
+ gpio |= 0x01; /* GPIO0 = 1 */
+ gpio &= (~0x10); /* GPIO4 = 0 */
+ sys0 = sys0 & 0x0f;
+ sys0 |= 0xe0;
+ } else {
+ gpio &= (~0x01); /* GPIO0 = 0 */
+ gpio |= 0x10; /* GPIO4 = 1 */
+ sys0 = sys0 & (~0xc0);
+ }
+
+ deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
+
+ /* demod adc */
+ ret = rtl2831_wr_reg(d, SYS_SYS0, sys0);
+ if (ret)
+ goto err;
+
+ /* tuner power, write GPIOs */
+ ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ deb_info("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl2831u_rc_query(struct dvb_usb_device *d)
+{
+ int ret, i;
+ struct rtl28xxu_priv *priv = d->priv;
+ u8 buf[5];
+ u32 rc_code;
+ struct rtl28xxu_reg_val rc_nec_tab[] = {
+ { 0x3033, 0x80 },
+ { 0x3020, 0x43 },
+ { 0x3021, 0x16 },
+ { 0x3022, 0x16 },
+ { 0x3023, 0x5a },
+ { 0x3024, 0x2d },
+ { 0x3025, 0x16 },
+ { 0x3026, 0x01 },
+ { 0x3028, 0xb0 },
+ { 0x3029, 0x04 },
+ { 0x302c, 0x88 },
+ { 0x302e, 0x13 },
+ { 0x3030, 0xdf },
+ { 0x3031, 0x05 },
+ };
+
+ /* init remote controller */
+ if (!priv->rc_active) {
+ for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
+ ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg,
+ rc_nec_tab[i].val);
+ if (ret)
+ goto err;
+ }
+ priv->rc_active = true;
+ }
+
+ ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5);
+ if (ret)
+ goto err;
+
+ if (buf[4] & 0x01) {
+ if (buf[2] == (u8) ~buf[3]) {
+ if (buf[0] == (u8) ~buf[1]) {
+ /* NEC standard (16 bit) */
+ rc_code = buf[0] << 8 | buf[2];
+ } else {
+ /* NEC extended (24 bit) */
+ rc_code = buf[0] << 16 |
+ buf[1] << 8 | buf[2];
+ }
+ } else {
+ /* NEC full (32 bit) */
+ rc_code = buf[0] << 24 | buf[1] << 16 |
+ buf[2] << 8 | buf[3];
+ }
+
+ rc_keydown(d->rc_dev, rc_code, 0);
+
+ ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1);
+ if (ret)
+ goto err;
+
+ /* repeated intentionally to avoid extra keypress */
+ ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1);
+ if (ret)
+ goto err;
+ }
+
+ return ret;
+err:
+ deb_info("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int rtl2832u_rc_query(struct dvb_usb_device *d)
+{
+ int ret, i;
+ struct rtl28xxu_priv *priv = d->priv;
+ u8 buf[128];
+ int len;
+ struct rtl28xxu_reg_val rc_nec_tab[] = {
+ { IR_RX_CTRL, 0x20 },
+ { IR_RX_BUF_CTRL, 0x80 },
+ { IR_RX_IF, 0xff },
+ { IR_RX_IE, 0xff },
+ { IR_MAX_DURATION0, 0xd0 },
+ { IR_MAX_DURATION1, 0x07 },
+ { IR_IDLE_LEN0, 0xc0 },
+ { IR_IDLE_LEN1, 0x00 },
+ { IR_GLITCH_LEN, 0x03 },
+ { IR_RX_CLK, 0x09 },
+ { IR_RX_CFG, 0x1c },
+ { IR_MAX_H_TOL_LEN, 0x1e },
+ { IR_MAX_L_TOL_LEN, 0x1e },
+ { IR_RX_CTRL, 0x80 },
+ };
+
+ /* init remote controller */
+ if (!priv->rc_active) {
+ for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
+ ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg,
+ rc_nec_tab[i].val);
+ if (ret)
+ goto err;
+ }
+ priv->rc_active = true;
+ }
+
+ ret = rtl2831_rd_reg(d, IR_RX_IF, &buf[0]);
+ if (ret)
+ goto err;
+
+ if (buf[0] != 0x83)
+ goto exit;
+
+ ret = rtl2831_rd_reg(d, IR_RX_BC, &buf[0]);
+ if (ret)
+ goto err;
+
+ len = buf[0];
+ ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
+
+ /* TODO: pass raw IR to Kernel IR decoder */
+
+ ret = rtl2831_wr_reg(d, IR_RX_IF, 0x03);
+ ret = rtl2831_wr_reg(d, IR_RX_BUF_CTRL, 0x80);
+ ret = rtl2831_wr_reg(d, IR_RX_CTRL, 0x80);
+
+exit:
+ return ret;
+err:
+ deb_info("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+enum rtl28xxu_usb_table_entry {
+ RTL2831U_0BDA_2831,
+ RTL2831U_14AA_0160,
+ RTL2831U_14AA_0161,
+};
+
+static struct usb_device_id rtl28xxu_table[] = {
+ /* RTL2831U */
+ [RTL2831U_0BDA_2831] = {
+ USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U)},
+ [RTL2831U_14AA_0160] = {
+ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT)},
+ [RTL2831U_14AA_0161] = {
+ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)},
+
+ /* RTL2832U */
+ {} /* terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, rtl28xxu_table);
+
+static struct dvb_usb_device_properties rtl28xxu_properties[] = {
+ {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .no_reconnect = 1,
+
+ .size_of_priv = sizeof(struct rtl28xxu_priv),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {
+ {
+ .frontend_attach = rtl2831u_frontend_attach,
+ .tuner_attach = rtl2831u_tuner_attach,
+ .streaming_ctrl = rtl28xxu_streaming_ctrl,
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x81,
+ .u = {
+ .bulk = {
+ .buffersize = 8*512,
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ .power_ctrl = rtl28xxu_power_ctrl,
+
+ .rc.core = {
+ .protocol = RC_TYPE_NEC,
+ .module_name = "rtl28xxu",
+ .rc_query = rtl2831u_rc_query,
+ .rc_interval = 400,
+ .allowed_protos = RC_TYPE_NEC,
+ .rc_codes = RC_MAP_EMPTY,
+ },
+
+ .i2c_algo = &rtl28xxu_i2c_algo,
+
+ .num_device_descs = 2,
+ .devices = {
+ {
+ .name = "Realtek RTL2831U reference design",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2831U_0BDA_2831],
+ },
+ },
+ {
+ .name = "Freecom USB2.0 DVB-T",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2831U_14AA_0160],
+ &rtl28xxu_table[RTL2831U_14AA_0161],
+ },
+ },
+ }
+ },
+ {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .no_reconnect = 1,
+
+ .size_of_priv = sizeof(struct rtl28xxu_priv),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {
+ {
+ .frontend_attach = rtl2832u_frontend_attach,
+ .tuner_attach = rtl2832u_tuner_attach,
+ .streaming_ctrl = rtl28xxu_streaming_ctrl,
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x81,
+ .u = {
+ .bulk = {
+ .buffersize = 8*512,
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ .power_ctrl = rtl28xxu_power_ctrl,
+
+ .rc.core = {
+ .protocol = RC_TYPE_NEC,
+ .module_name = "rtl28xxu",
+ .rc_query = rtl2832u_rc_query,
+ .rc_interval = 400,
+ .allowed_protos = RC_TYPE_NEC,
+ .rc_codes = RC_MAP_EMPTY,
+ },
+
+ .i2c_algo = &rtl28xxu_i2c_algo,
+
+ .num_device_descs = 0, /* disabled as no support for RTL2832 */
+ .devices = {
+ {
+ .name = "Realtek RTL2832U reference design",
+ },
+ }
+ },
+
+};
+
+static int rtl28xxu_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int ret, i;
+ int properties_count = ARRAY_SIZE(rtl28xxu_properties);
+ struct dvb_usb_device *d;
+
+ deb_info("%s: interface=%d\n", __func__,
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return 0;
+
+ for (i = 0; i < properties_count; i++) {
+ ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i],
+ THIS_MODULE, &d, adapter_nr);
+ if (ret == 0 || ret != -ENODEV)
+ break;
+ }
+
+ if (ret)
+ goto err;
+
+ /* init USB endpoints */
+ ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09);
+ if (ret)
+ goto err;
+
+ ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
+ if (ret)
+ goto err;
+
+ ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ deb_info("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static struct usb_driver rtl28xxu_driver = {
+ .name = "dvb_usb_rtl28xxu",
+ .probe = rtl28xxu_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = rtl28xxu_table,
+};
+
+/* module stuff */
+static int __init rtl28xxu_module_init(void)
+{
+ int ret;
+
+ deb_info("%s:\n", __func__);
+
+ ret = usb_register(&rtl28xxu_driver);
+ if (ret)
+ err("usb_register failed=%d", ret);
+
+ return ret;
+}
+
+static void __exit rtl28xxu_module_exit(void)
+{
+ deb_info("%s:\n", __func__);
+
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&rtl28xxu_driver);
+}
+
+module_init(rtl28xxu_module_init);
+module_exit(rtl28xxu_module_exit);
+
+MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.h b/drivers/media/dvb/dvb-usb/rtl28xxu.h
new file mode 100644
index 000000000000..90f3bb4f4c0e
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.h
@@ -0,0 +1,264 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL28XXU_H
+#define RTL28XXU_H
+
+#define DVB_USB_LOG_PREFIX "rtl28xxu"
+#include "dvb-usb.h"
+
+#define deb_info(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x01, args)
+#define deb_rc(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x02, args)
+#define deb_xfer(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x04, args)
+#define deb_reg(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x08, args)
+#define deb_i2c(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x10, args)
+#define deb_fw(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x20, args)
+
+#define deb_dump(r, t, v, i, b, l, func) { \
+ int loop_; \
+ func("%02x %02x %02x %02x %02x %02x %02x %02x", \
+ t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
+ if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
+ func(" >>> "); \
+ else \
+ func(" <<< "); \
+ for (loop_ = 0; loop_ < l; loop_++) \
+ func("%02x ", b[loop_]); \
+ func("\n");\
+}
+
+/*
+ * USB commands
+ * (usb_control_msg() index parameter)
+ */
+
+#define DEMOD 0x0000
+#define USB 0x0100
+#define SYS 0x0200
+#define I2C 0x0300
+#define I2C_DA 0x0600
+
+#define CMD_WR_FLAG 0x0010
+#define CMD_DEMOD_RD 0x0000
+#define CMD_DEMOD_WR 0x0010
+#define CMD_USB_RD 0x0100
+#define CMD_USB_WR 0x0110
+#define CMD_SYS_RD 0x0200
+#define CMD_IR_RD 0x0201
+#define CMD_IR_WR 0x0211
+#define CMD_SYS_WR 0x0210
+#define CMD_I2C_RD 0x0300
+#define CMD_I2C_WR 0x0310
+#define CMD_I2C_DA_RD 0x0600
+#define CMD_I2C_DA_WR 0x0610
+
+
+struct rtl28xxu_priv {
+ u8 chip_id;
+ u8 tuner;
+ u8 page; /* integrated demod active register page */
+ bool rc_active;
+};
+
+enum rtl28xxu_chip_id {
+ CHIP_ID_NONE,
+ CHIP_ID_RTL2831U,
+ CHIP_ID_RTL2832U,
+};
+
+enum rtl28xxu_tuner {
+ TUNER_NONE,
+
+ TUNER_RTL2830_QT1010,
+ TUNER_RTL2830_MT2060,
+ TUNER_RTL2830_MXL5005S,
+
+ TUNER_RTL2832_MT2266,
+ TUNER_RTL2832_FC2580,
+ TUNER_RTL2832_MT2063,
+ TUNER_RTL2832_MAX3543,
+ TUNER_RTL2832_TUA9001,
+ TUNER_RTL2832_MXL5007T,
+ TUNER_RTL2832_FC0012,
+ TUNER_RTL2832_E4000,
+ TUNER_RTL2832_TDA18272,
+ TUNER_RTL2832_FC0013,
+};
+
+struct rtl28xxu_req {
+ u16 value;
+ u16 index;
+ u16 size;
+ u8 *data;
+};
+
+struct rtl28xxu_reg_val {
+ u16 reg;
+ u8 val;
+};
+
+/*
+ * memory map
+ *
+ * 0x0000 DEMOD : demodulator
+ * 0x2000 USB : SIE, USB endpoint, debug, DMA
+ * 0x3000 SYS : system
+ * 0xfc00 RC : remote controller (not RTL2831U)
+ */
+
+/*
+ * USB registers
+ */
+/* SIE Control Registers */
+#define USB_SYSCTL 0x2000 /* USB system control */
+#define USB_SYSCTL_0 0x2000 /* USB system control */
+#define USB_SYSCTL_1 0x2001 /* USB system control */
+#define USB_SYSCTL_2 0x2002 /* USB system control */
+#define USB_SYSCTL_3 0x2003 /* USB system control */
+#define USB_IRQSTAT 0x2008 /* SIE interrupt status */
+#define USB_IRQEN 0x200C /* SIE interrupt enable */
+#define USB_CTRL 0x2010 /* USB control */
+#define USB_STAT 0x2014 /* USB status */
+#define USB_DEVADDR 0x2018 /* USB device address */
+#define USB_TEST 0x201C /* USB test mode */
+#define USB_FRAME_NUMBER 0x2020 /* frame number */
+#define USB_FIFO_ADDR 0x2028 /* address of SIE FIFO RAM */
+#define USB_FIFO_CMD 0x202A /* SIE FIFO RAM access command */
+#define USB_FIFO_DATA 0x2030 /* SIE FIFO RAM data */
+/* Endpoint Registers */
+#define EP0_SETUPA 0x20F8 /* EP 0 setup packet lower byte */
+#define EP0_SETUPB 0x20FC /* EP 0 setup packet higher byte */
+#define USB_EP0_CFG 0x2104 /* EP 0 configure */
+#define USB_EP0_CTL 0x2108 /* EP 0 control */
+#define USB_EP0_STAT 0x210C /* EP 0 status */
+#define USB_EP0_IRQSTAT 0x2110 /* EP 0 interrupt status */
+#define USB_EP0_IRQEN 0x2114 /* EP 0 interrupt enable */
+#define USB_EP0_MAXPKT 0x2118 /* EP 0 max packet size */
+#define USB_EP0_BC 0x2120 /* EP 0 FIFO byte counter */
+#define USB_EPA_CFG 0x2144 /* EP A configure */
+#define USB_EPA_CFG_0 0x2144 /* EP A configure */
+#define USB_EPA_CFG_1 0x2145 /* EP A configure */
+#define USB_EPA_CFG_2 0x2146 /* EP A configure */
+#define USB_EPA_CFG_3 0x2147 /* EP A configure */
+#define USB_EPA_CTL 0x2148 /* EP A control */
+#define USB_EPA_CTL_0 0x2148 /* EP A control */
+#define USB_EPA_CTL_1 0x2149 /* EP A control */
+#define USB_EPA_CTL_2 0x214A /* EP A control */
+#define USB_EPA_CTL_3 0x214B /* EP A control */
+#define USB_EPA_STAT 0x214C /* EP A status */
+#define USB_EPA_IRQSTAT 0x2150 /* EP A interrupt status */
+#define USB_EPA_IRQEN 0x2154 /* EP A interrupt enable */
+#define USB_EPA_MAXPKT 0x2158 /* EP A max packet size */
+#define USB_EPA_MAXPKT_0 0x2158 /* EP A max packet size */
+#define USB_EPA_MAXPKT_1 0x2159 /* EP A max packet size */
+#define USB_EPA_MAXPKT_2 0x215A /* EP A max packet size */
+#define USB_EPA_MAXPKT_3 0x215B /* EP A max packet size */
+#define USB_EPA_FIFO_CFG 0x2160 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */
+/* Debug Registers */
+#define USB_PHYTSTDIS 0x2F04 /* PHY test disable */
+#define USB_TOUT_VAL 0x2F08 /* USB time-out time */
+#define USB_VDRCTRL 0x2F10 /* UTMI vendor signal control */
+#define USB_VSTAIN 0x2F14 /* UTMI vendor signal status in */
+#define USB_VLOADM 0x2F18 /* UTMI load vendor signal status in */
+#define USB_VSTAOUT 0x2F1C /* UTMI vendor signal status out */
+#define USB_UTMI_TST 0x2F80 /* UTMI test */
+#define USB_UTMI_STATUS 0x2F84 /* UTMI status */
+#define USB_TSTCTL 0x2F88 /* test control */
+#define USB_TSTCTL2 0x2F8C /* test control 2 */
+#define USB_PID_FORCE 0x2F90 /* force PID */
+#define USB_PKTERR_CNT 0x2F94 /* packet error counter */
+#define USB_RXERR_CNT 0x2F98 /* RX error counter */
+#define USB_MEM_BIST 0x2F9C /* MEM BIST test */
+#define USB_SLBBIST 0x2FA0 /* self-loop-back BIST */
+#define USB_CNTTEST 0x2FA4 /* counter test */
+#define USB_PHYTST 0x2FC0 /* USB PHY test */
+#define USB_DBGIDX 0x2FF0 /* select individual block debug signal */
+#define USB_DBGMUX 0x2FF4 /* debug signal module mux */
+
+/*
+ * SYS registers
+ */
+/* demod control registers */
+#define SYS_SYS0 0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */
+#define SYS_DEMOD_CTL 0x3000 /* control register for DVB-T demodulator */
+/* GPIO registers */
+#define SYS_GPIO_OUT_VAL 0x3001 /* output value of GPIO */
+#define SYS_GPIO_IN_VAL 0x3002 /* input value of GPIO */
+#define SYS_GPIO_OUT_EN 0x3003 /* output enable of GPIO */
+#define SYS_SYS1 0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */
+#define SYS_GPIO_DIR 0x3004 /* direction control for GPIO */
+#define SYS_SYSINTE 0x3005 /* system interrupt enable */
+#define SYS_SYSINTS 0x3006 /* system interrupt status */
+#define SYS_GPIO_CFG0 0x3007 /* PAD configuration for GPIO0-GPIO3 */
+#define SYS_SYS2 0x3008 /* include GP_CFG1 and 3 reserved bytes */
+#define SYS_GPIO_CFG1 0x3008 /* PAD configuration for GPIO4 */
+#define SYS_DEMOD_CTL1 0x300B
+
+/* IrDA registers */
+#define SYS_IRRC_PSR 0x3020 /* IR protocol selection */
+#define SYS_IRRC_PER 0x3024 /* IR protocol extension */
+#define SYS_IRRC_SF 0x3028 /* IR sampling frequency */
+#define SYS_IRRC_DPIR 0x302C /* IR data package interval */
+#define SYS_IRRC_CR 0x3030 /* IR control */
+#define SYS_IRRC_RP 0x3034 /* IR read port */
+#define SYS_IRRC_SR 0x3038 /* IR status */
+/* I2C master registers */
+#define SYS_I2CCR 0x3040 /* I2C clock */
+#define SYS_I2CMCR 0x3044 /* I2C master control */
+#define SYS_I2CMSTR 0x3048 /* I2C master SCL timing */
+#define SYS_I2CMSR 0x304C /* I2C master status */
+#define SYS_I2CMFR 0x3050 /* I2C master FIFO */
+
+/*
+ * IR registers
+ */
+#define IR_RX_BUF 0xFC00
+#define IR_RX_IE 0xFD00
+#define IR_RX_IF 0xFD01
+#define IR_RX_CTRL 0xFD02
+#define IR_RX_CFG 0xFD03
+#define IR_MAX_DURATION0 0xFD04
+#define IR_MAX_DURATION1 0xFD05
+#define IR_IDLE_LEN0 0xFD06
+#define IR_IDLE_LEN1 0xFD07
+#define IR_GLITCH_LEN 0xFD08
+#define IR_RX_BUF_CTRL 0xFD09
+#define IR_RX_BUF_DATA 0xFD0A
+#define IR_RX_BC 0xFD0B
+#define IR_RX_CLK 0xFD0C
+#define IR_RX_C_COUNT_L 0xFD0D
+#define IR_RX_C_COUNT_H 0xFD0E
+#define IR_SUSPEND_CTRL 0xFD10
+#define IR_ERR_TOL_CTRL 0xFD11
+#define IR_UNIT_LEN 0xFD12
+#define IR_ERR_TOL_LEN 0xFD13
+#define IR_MAX_H_TOL_LEN 0xFD14
+#define IR_MAX_L_TOL_LEN 0xFD15
+#define IR_MASK_CTRL 0xFD16
+#define IR_MASK_DATA 0xFD17
+#define IR_RES_MASK_ADDR 0xFD18
+#define IR_RES_MASK_T_LEN 0xFD19
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
index 56acf8e55d50..e53a1061cb8e 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -75,10 +75,18 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
struct ttusb2_state *st = d->priv;
- u8 s[wlen+4],r[64] = { 0 };
+ u8 *s, *r = NULL;
int ret = 0;
- memset(s,0,wlen+4);
+ s = kzalloc(wlen+4, GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ r = kzalloc(64, GFP_KERNEL);
+ if (!r) {
+ kfree(s);
+ return -ENOMEM;
+ }
s[0] = 0xaa;
s[1] = ++st->id;
@@ -94,12 +102,17 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
r[2] != cmd ||
(rlen > 0 && r[3] != rlen)) {
warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]);
+ kfree(s);
+ kfree(r);
return -EIO;
}
if (rlen > 0)
memcpy(rbuf, &r[4], rlen);
+ kfree(s);
+ kfree(r);
+
return 0;
}
@@ -384,7 +397,7 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
memcpy(&obuf[3], msg[i].buf, msg[i].len);
- if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) {
+ if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) {
err("i2c transfer failed.");
break;
}
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
index 2bb8d4cc8d88..5eab468dd904 100644
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c
@@ -135,9 +135,9 @@ static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
return 0;
}
-static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static int vp702x_fe_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct vp702x_fe_state *st = fe->demodulator_priv;
struct vp702x_device_state *dst = st->d->priv;
u32 freq = fep->frequency/1000;
@@ -155,14 +155,14 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
cmd[1] = freq & 0xff;
cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */
- sr = (u64) (fep->u.qpsk.symbol_rate/1000) << 20;
+ sr = (u64) (fep->symbol_rate/1000) << 20;
do_div(sr,88000);
cmd[3] = (sr >> 12) & 0xff;
cmd[4] = (sr >> 4) & 0xff;
cmd[5] = (sr << 4) & 0xf0;
deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n",
- fep->frequency,freq,freq, fep->u.qpsk.symbol_rate,
+ fep->frequency, freq, freq, fep->symbol_rate,
(unsigned long) sr, (unsigned long) sr);
/* if (fep->inversion == INVERSION_ON)
@@ -171,7 +171,7 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
if (st->voltage == SEC_VOLTAGE_18)
cmd[6] |= 0x40;
-/* if (fep->u.qpsk.symbol_rate > 8000000)
+/* if (fep->symbol_rate > 8000000)
cmd[6] |= 0x20;
if (fep->frequency < 1531000)
@@ -211,13 +211,6 @@ static int vp702x_fe_sleep(struct dvb_frontend *fe)
return 0;
}
-static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
-{
- deb_fe("%s\n",__func__);
- return 0;
-}
-
static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
struct dvb_diseqc_master_cmd *m)
{
@@ -350,9 +343,9 @@ error:
static struct dvb_frontend_ops vp702x_fe_ops = {
+ .delsys = { SYS_DVBS },
.info = {
.name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1000, /* kHz for QPSK frontends */
@@ -371,7 +364,6 @@ static struct dvb_frontend_ops vp702x_fe_ops = {
.sleep = vp702x_fe_sleep,
.set_frontend = vp702x_fe_set_frontend,
- .get_frontend = vp702x_fe_get_frontend,
.get_tune_settings = vp702x_fe_get_tune_settings,
.read_status = vp702x_fe_read_status,
diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c
index 8452eef90322..b8825b18c003 100644
--- a/drivers/media/dvb/dvb-usb/vp7045-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp7045-fe.c
@@ -103,9 +103,9 @@ static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
return 0;
}
-static int vp7045_fe_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static int vp7045_fe_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct vp7045_fe_state *state = fe->demodulator_priv;
u8 buf[5];
u32 freq = fep->frequency / 1000;
@@ -115,25 +115,24 @@ static int vp7045_fe_set_frontend(struct dvb_frontend* fe,
buf[2] = freq & 0xff;
buf[3] = 0;
- switch (fep->u.ofdm.bandwidth) {
- case BANDWIDTH_8_MHZ: buf[4] = 8; break;
- case BANDWIDTH_7_MHZ: buf[4] = 7; break;
- case BANDWIDTH_6_MHZ: buf[4] = 6; break;
- case BANDWIDTH_AUTO: return -EOPNOTSUPP;
- default:
- return -EINVAL;
+ switch (fep->bandwidth_hz) {
+ case 8000000:
+ buf[4] = 8;
+ break;
+ case 7000000:
+ buf[4] = 7;
+ break;
+ case 6000000:
+ buf[4] = 6;
+ break;
+ default:
+ return -EINVAL;
}
vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200);
return 0;
}
-static int vp7045_fe_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
-{
- return 0;
-}
-
static void vp7045_fe_release(struct dvb_frontend* fe)
{
struct vp7045_fe_state *state = fe->demodulator_priv;
@@ -159,9 +158,9 @@ error:
static struct dvb_frontend_ops vp7045_fe_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "Twinhan VP7045/46 USB DVB-T",
- .type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 1000,
@@ -181,7 +180,6 @@ static struct dvb_frontend_ops vp7045_fe_ops = {
.sleep = vp7045_fe_sleep,
.set_frontend = vp7045_fe_set_frontend,
- .get_frontend = vp7045_fe_get_frontend,
.get_tune_settings = vp7045_fe_get_tune_settings,
.read_status = vp7045_fe_read_status,
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
index 489ae8245867..d1a1a1324ef8 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -335,7 +335,7 @@ static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
* (not supported by the AVC standard)
*/
static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params)
+ struct dtv_frontend_properties *p)
{
struct avc_command_frame *c = (void *)fdtv->avc_data;
@@ -349,15 +349,15 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
else
c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK;
- c->operand[4] = (params->frequency >> 24) & 0xff;
- c->operand[5] = (params->frequency >> 16) & 0xff;
- c->operand[6] = (params->frequency >> 8) & 0xff;
- c->operand[7] = params->frequency & 0xff;
+ c->operand[4] = (p->frequency >> 24) & 0xff;
+ c->operand[5] = (p->frequency >> 16) & 0xff;
+ c->operand[6] = (p->frequency >> 8) & 0xff;
+ c->operand[7] = p->frequency & 0xff;
- c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff;
- c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff;
+ c->operand[8] = ((p->symbol_rate / 1000) >> 8) & 0xff;
+ c->operand[9] = (p->symbol_rate / 1000) & 0xff;
- switch (params->u.qpsk.fec_inner) {
+ switch (p->fec_inner) {
case FEC_1_2: c->operand[10] = 0x1; break;
case FEC_2_3: c->operand[10] = 0x2; break;
case FEC_3_4: c->operand[10] = 0x3; break;
@@ -392,10 +392,11 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
default: c->operand[13] = 0x2; break;
}
switch (fdtv->fe.dtv_property_cache.rolloff) {
- case ROLLOFF_AUTO: c->operand[14] = 0x2; break;
case ROLLOFF_35: c->operand[14] = 0x2; break;
case ROLLOFF_20: c->operand[14] = 0x0; break;
case ROLLOFF_25: c->operand[14] = 0x1; break;
+ case ROLLOFF_AUTO:
+ default: c->operand[14] = 0x2; break;
/* case ROLLOFF_NONE: c->operand[14] = 0xff; break; */
}
switch (fdtv->fe.dtv_property_cache.pilot) {
@@ -415,7 +416,7 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
}
static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params)
+ struct dtv_frontend_properties *p)
{
struct avc_command_frame *c = (void *)fdtv->avc_data;
@@ -434,8 +435,8 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
| 1 << 4 /* Frequency */
| 1 << 3 /* Symbol_Rate */
| 0 << 2 /* FEC_outer */
- | (params->u.qam.fec_inner != FEC_AUTO ? 1 << 1 : 0)
- | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0);
+ | (p->fec_inner != FEC_AUTO ? 1 << 1 : 0)
+ | (p->modulation != QAM_AUTO ? 1 << 0 : 0);
/* multiplex_valid_flags, low byte */
c->operand[6] = 0 << 7 /* NetworkID */
@@ -446,15 +447,15 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
c->operand[9] = 0x00;
c->operand[10] = 0x00;
- c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6);
- c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff;
- c->operand[13] = (params->frequency / 4000) & 0xff;
- c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff;
- c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff;
- c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0;
+ c->operand[11] = (((p->frequency / 4000) >> 16) & 0xff) | (2 << 6);
+ c->operand[12] = ((p->frequency / 4000) >> 8) & 0xff;
+ c->operand[13] = (p->frequency / 4000) & 0xff;
+ c->operand[14] = ((p->symbol_rate / 1000) >> 12) & 0xff;
+ c->operand[15] = ((p->symbol_rate / 1000) >> 4) & 0xff;
+ c->operand[16] = ((p->symbol_rate / 1000) << 4) & 0xf0;
c->operand[17] = 0x00;
- switch (params->u.qpsk.fec_inner) {
+ switch (p->fec_inner) {
case FEC_1_2: c->operand[18] = 0x1; break;
case FEC_2_3: c->operand[18] = 0x2; break;
case FEC_3_4: c->operand[18] = 0x3; break;
@@ -466,7 +467,7 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
default: c->operand[18] = 0x0;
}
- switch (params->u.qam.modulation) {
+ switch (p->modulation) {
case QAM_16: c->operand[19] = 0x08; break;
case QAM_32: c->operand[19] = 0x10; break;
case QAM_64: c->operand[19] = 0x18; break;
@@ -483,9 +484,8 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
}
static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params)
+ struct dtv_frontend_properties *p)
{
- struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
struct avc_command_frame *c = (void *)fdtv->avc_data;
c->opcode = AVC_OPCODE_DSD;
@@ -500,42 +500,42 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
c->operand[5] =
0 << 7 /* reserved */
| 1 << 6 /* CenterFrequency */
- | (ofdm->bandwidth != BANDWIDTH_AUTO ? 1 << 5 : 0)
- | (ofdm->constellation != QAM_AUTO ? 1 << 4 : 0)
- | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0)
- | (ofdm->code_rate_HP != FEC_AUTO ? 1 << 2 : 0)
- | (ofdm->code_rate_LP != FEC_AUTO ? 1 << 1 : 0)
- | (ofdm->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0);
+ | (p->bandwidth_hz != 0 ? 1 << 5 : 0)
+ | (p->modulation != QAM_AUTO ? 1 << 4 : 0)
+ | (p->hierarchy != HIERARCHY_AUTO ? 1 << 3 : 0)
+ | (p->code_rate_HP != FEC_AUTO ? 1 << 2 : 0)
+ | (p->code_rate_LP != FEC_AUTO ? 1 << 1 : 0)
+ | (p->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0);
/* multiplex_valid_flags, low byte */
c->operand[6] =
0 << 7 /* NetworkID */
- | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0)
+ | (p->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0)
| 0 << 5 /* OtherFrequencyFlag */
| 0 << 0 /* reserved */ ;
c->operand[7] = 0x0;
- c->operand[8] = (params->frequency / 10) >> 24;
- c->operand[9] = ((params->frequency / 10) >> 16) & 0xff;
- c->operand[10] = ((params->frequency / 10) >> 8) & 0xff;
- c->operand[11] = (params->frequency / 10) & 0xff;
-
- switch (ofdm->bandwidth) {
- case BANDWIDTH_7_MHZ: c->operand[12] = 0x20; break;
- case BANDWIDTH_8_MHZ:
- case BANDWIDTH_6_MHZ: /* not defined by AVC spec */
- case BANDWIDTH_AUTO:
+ c->operand[8] = (p->frequency / 10) >> 24;
+ c->operand[9] = ((p->frequency / 10) >> 16) & 0xff;
+ c->operand[10] = ((p->frequency / 10) >> 8) & 0xff;
+ c->operand[11] = (p->frequency / 10) & 0xff;
+
+ switch (p->bandwidth_hz) {
+ case 7000000: c->operand[12] = 0x20; break;
+ case 8000000:
+ case 6000000: /* not defined by AVC spec */
+ case 0:
default: c->operand[12] = 0x00;
}
- switch (ofdm->constellation) {
+ switch (p->modulation) {
case QAM_16: c->operand[13] = 1 << 6; break;
case QAM_64: c->operand[13] = 2 << 6; break;
case QPSK:
default: c->operand[13] = 0x00;
}
- switch (ofdm->hierarchy_information) {
+ switch (p->hierarchy) {
case HIERARCHY_1: c->operand[13] |= 1 << 3; break;
case HIERARCHY_2: c->operand[13] |= 2 << 3; break;
case HIERARCHY_4: c->operand[13] |= 3 << 3; break;
@@ -544,7 +544,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
default: break;
}
- switch (ofdm->code_rate_HP) {
+ switch (p->code_rate_HP) {
case FEC_2_3: c->operand[13] |= 1; break;
case FEC_3_4: c->operand[13] |= 2; break;
case FEC_5_6: c->operand[13] |= 3; break;
@@ -553,7 +553,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
default: break;
}
- switch (ofdm->code_rate_LP) {
+ switch (p->code_rate_LP) {
case FEC_2_3: c->operand[14] = 1 << 5; break;
case FEC_3_4: c->operand[14] = 2 << 5; break;
case FEC_5_6: c->operand[14] = 3 << 5; break;
@@ -562,7 +562,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
default: c->operand[14] = 0x00; break;
}
- switch (ofdm->guard_interval) {
+ switch (p->guard_interval) {
case GUARD_INTERVAL_1_16: c->operand[14] |= 1 << 3; break;
case GUARD_INTERVAL_1_8: c->operand[14] |= 2 << 3; break;
case GUARD_INTERVAL_1_4: c->operand[14] |= 3 << 3; break;
@@ -571,7 +571,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
default: break;
}
- switch (ofdm->transmission_mode) {
+ switch (p->transmission_mode) {
case TRANSMISSION_MODE_8K: c->operand[14] |= 1 << 1; break;
case TRANSMISSION_MODE_2K:
case TRANSMISSION_MODE_AUTO:
@@ -585,7 +585,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
}
int avc_tuner_dsd(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params)
+ struct dtv_frontend_properties *p)
{
struct avc_command_frame *c = (void *)fdtv->avc_data;
int pos, ret;
@@ -597,9 +597,9 @@ int avc_tuner_dsd(struct firedtv *fdtv,
switch (fdtv->type) {
case FIREDTV_DVB_S:
- case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break;
- case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break;
- case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break;
+ case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, p); break;
+ case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, p); break;
+ case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, p); break;
default:
BUG();
}
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c
index fd8bbbfa5c59..eb7496eab130 100644
--- a/drivers/media/dvb/firewire/firedtv-dvb.c
+++ b/drivers/media/dvb/firewire/firedtv-dvb.c
@@ -203,7 +203,9 @@ int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
if (err)
goto fail_rem_frontend;
- dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
+ err = dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
+ if (err)
+ goto fail_disconnect_frontend;
fdtv_frontend_init(fdtv, name);
err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
@@ -218,6 +220,7 @@ int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
fail_net_release:
dvb_net_release(&fdtv->dvbnet);
+fail_disconnect_frontend:
fdtv->demux.dmx.close(&fdtv->demux.dmx);
fail_rem_frontend:
fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c
index 8748a61be73d..6fe9793b98b3 100644
--- a/drivers/media/dvb/firewire/firedtv-fe.c
+++ b/drivers/media/dvb/firewire/firedtv-fe.c
@@ -141,28 +141,12 @@ static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks)
return -EOPNOTSUPP;
}
-static int fdtv_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int fdtv_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct firedtv *fdtv = fe->sec_priv;
- return avc_tuner_dsd(fdtv, params);
-}
-
-static int fdtv_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- return -EOPNOTSUPP;
-}
-
-static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp)
-{
- return 0;
-}
-
-static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp)
-{
- return 0;
+ return avc_tuner_dsd(fdtv, p);
}
void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
@@ -174,10 +158,6 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
ops->sleep = fdtv_sleep;
ops->set_frontend = fdtv_set_frontend;
- ops->get_frontend = fdtv_get_frontend;
-
- ops->get_property = fdtv_get_property;
- ops->set_property = fdtv_set_property;
ops->read_status = fdtv_read_status;
ops->read_ber = fdtv_read_ber;
@@ -192,7 +172,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
switch (fdtv->type) {
case FIREDTV_DVB_S:
- fi->type = FE_QPSK;
+ ops->delsys[0] = SYS_DVBS;
fi->frequency_min = 950000;
fi->frequency_max = 2150000;
@@ -211,7 +191,8 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
break;
case FIREDTV_DVB_S2:
- fi->type = FE_QPSK;
+ ops->delsys[0] = SYS_DVBS;
+ ops->delsys[1] = SYS_DVBS2;
fi->frequency_min = 950000;
fi->frequency_max = 2150000;
@@ -231,7 +212,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
break;
case FIREDTV_DVB_C:
- fi->type = FE_QAM;
+ ops->delsys[0] = SYS_DVBC_ANNEX_A;
fi->frequency_min = 47000000;
fi->frequency_max = 866000000;
@@ -249,7 +230,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
break;
case FIREDTV_DVB_T:
- fi->type = FE_OFDM;
+ ops->delsys[0] = SYS_DVBT;
fi->frequency_min = 49000000;
fi->frequency_max = 861000000;
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 864b6274c729..e24ec539a5fd 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -20,7 +20,6 @@
#include <linux/workqueue.h>
#include <asm/page.h>
-#include <asm/system.h>
#include <dvb_demux.h>
diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h
index bd00b04e079d..4fdcd8cb7530 100644
--- a/drivers/media/dvb/firewire/firedtv.h
+++ b/drivers/media/dvb/firewire/firedtv.h
@@ -112,8 +112,8 @@ struct firedtv {
/* firedtv-avc.c */
int avc_recv(struct firedtv *fdtv, void *data, size_t length);
int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat);
-struct dvb_frontend_parameters;
-int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params);
+struct dtv_frontend_properties;
+int avc_tuner_dsd(struct firedtv *fdtv, struct dtv_frontend_properties *params);
int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]);
int avc_tuner_get_ts(struct firedtv *fdtv);
int avc_identify_subunit(struct firedtv *fdtv);
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 4a2d2e6c91ab..21246707fbfb 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -404,6 +404,13 @@ config DVB_EC100
help
Say Y when you want to support this frontend.
+config DVB_HD29L2
+ tristate "HDIC HD29L2"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ Say Y when you want to support this frontend.
+
config DVB_STV0367
tristate "ST STV0367 based"
depends on DVB_CORE && I2C
@@ -418,6 +425,13 @@ config DVB_CXD2820R
help
Say Y when you want to support this frontend.
+config DVB_RTL2830
+ tristate "Realtek RTL2830 DVB-T"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ Say Y when you want to support this frontend.
+
comment "DVB-C (cable) frontends"
depends on DVB_CORE
@@ -691,6 +705,14 @@ config DVB_IT913X_FE
A DVB-T tuner module.
Say Y when you want to support this frontend.
+config DVB_M88RS2000
+ tristate "M88RS2000 DVB-S demodulator and tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module.
+ Say Y when you want to support this frontend.
+
comment "Tools to develop new frontends"
config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index f639f6781551..86fa808bf589 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -2,8 +2,8 @@
# Makefile for the kernel DVB frontend device drivers.
#
-ccflags-y += -Idrivers/media/dvb/dvb-core/
-ccflags-y += -Idrivers/media/common/tuners/
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core/
+ccflags-y += -I$(srctree)/drivers/media/common/tuners/
stb0899-objs = stb0899_drv.o stb0899_algo.o
stv0900-objs = stv0900_core.o stv0900_sw.o
@@ -84,6 +84,7 @@ obj-$(CONFIG_DVB_STV090x) += stv090x.o
obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
+obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
@@ -95,4 +96,6 @@ obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
obj-$(CONFIG_DVB_A8293) += a8293.o
obj-$(CONFIG_DVB_TDA10071) += tda10071.o
+obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
+obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
index 345311c33383..6bcbcf543b38 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -2,6 +2,7 @@
* Afatech AF9013 demodulator driver
*
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
*
* Thanks to Afatech who kindly provided information.
*
@@ -21,25 +22,15 @@
*
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-
-#include "dvb_frontend.h"
#include "af9013_priv.h"
-#include "af9013.h"
int af9013_debug;
+module_param_named(debug, af9013_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
struct af9013_state {
struct i2c_adapter *i2c;
- struct dvb_frontend frontend;
-
+ struct dvb_frontend fe;
struct af9013_config config;
/* tuner/demod RF and IF AGC limits used for signal strength calc */
@@ -48,107 +39,178 @@ struct af9013_state {
u32 ber;
u32 ucblocks;
u16 snr;
- u32 frequency;
- unsigned long next_statistics_check;
+ u32 bandwidth_hz;
+ fe_status_t fe_status;
+ unsigned long set_frontend_jiffies;
+ unsigned long read_status_jiffies;
+ bool first_tune;
+ bool i2c_gate_state;
+ unsigned int statistics_step:3;
+ struct delayed_work statistics_work;
};
-static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
-
-static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg,
- u8 *val, u8 len)
+/* write multiple registers */
+static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg,
+ const u8 *val, int len)
{
+ int ret;
u8 buf[3+len];
- struct i2c_msg msg = {
- .addr = state->config.demod_address,
- .flags = 0,
- .len = sizeof(buf),
- .buf = buf };
-
- buf[0] = reg >> 8;
- buf[1] = reg & 0xff;
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->config.i2c_addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ buf[0] = (reg >> 8) & 0xff;
+ buf[1] = (reg >> 0) & 0xff;
buf[2] = mbox;
memcpy(&buf[3], val, len);
- if (i2c_transfer(state->i2c, &msg, 1) != 1) {
- warn("I2C write failed reg:%04x len:%d", reg, len);
- return -EREMOTEIO;
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ warn("i2c wr failed=%d reg=%04x len=%d", ret, reg, len);
+ ret = -EREMOTEIO;
}
- return 0;
+ return ret;
}
-static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val,
- u8 len)
+/* read multiple registers */
+static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg,
+ u8 *val, int len)
{
- u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7);
- return af9013_write_regs(state, mbox, reg, val, len);
+ int ret;
+ u8 buf[3];
+ struct i2c_msg msg[2] = {
+ {
+ .addr = priv->config.i2c_addr,
+ .flags = 0,
+ .len = 3,
+ .buf = buf,
+ }, {
+ .addr = priv->config.i2c_addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = val,
+ }
+ };
+
+ buf[0] = (reg >> 8) & 0xff;
+ buf[1] = (reg >> 0) & 0xff;
+ buf[2] = mbox;
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret == 2) {
+ ret = 0;
+ } else {
+ warn("i2c rd failed=%d reg=%04x len=%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+ return ret;
}
-static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val,
- u8 len)
+/* write multiple registers */
+static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val,
+ int len)
+{
+ int ret, i;
+ u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0);
+
+ if ((priv->config.ts_mode == AF9013_TS_USB) &&
+ ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) {
+ mbox |= ((len - 1) << 2);
+ ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len);
+ } else {
+ for (i = 0; i < len; i++) {
+ ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1);
+ if (ret)
+ goto err;
+ }
+ }
+
+err:
+ return 0;
+}
+
+/* read multiple registers */
+static int af9013_rd_regs(struct af9013_state *priv, u16 reg, u8 *val, int len)
{
- u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7);
- return af9013_write_regs(state, mbox, reg, val, len);
+ int ret, i;
+ u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0);
+
+ if ((priv->config.ts_mode == AF9013_TS_USB) &&
+ ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) {
+ mbox |= ((len - 1) << 2);
+ ret = af9013_rd_regs_i2c(priv, mbox, reg, val, len);
+ } else {
+ for (i = 0; i < len; i++) {
+ ret = af9013_rd_regs_i2c(priv, mbox, reg+i, val+i, 1);
+ if (ret)
+ goto err;
+ }
+ }
+
+err:
+ return 0;
}
/* write single register */
-static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val)
+static int af9013_wr_reg(struct af9013_state *priv, u16 reg, u8 val)
{
- return af9013_write_ofdm_regs(state, reg, &val, 1);
+ return af9013_wr_regs(priv, reg, &val, 1);
}
/* read single register */
-static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val)
+static int af9013_rd_reg(struct af9013_state *priv, u16 reg, u8 *val)
{
- u8 obuf[3] = { reg >> 8, reg & 0xff, 0 };
- u8 ibuf[1];
- struct i2c_msg msg[2] = {
- {
- .addr = state->config.demod_address,
- .flags = 0,
- .len = sizeof(obuf),
- .buf = obuf
- }, {
- .addr = state->config.demod_address,
- .flags = I2C_M_RD,
- .len = sizeof(ibuf),
- .buf = ibuf
- }
- };
+ return af9013_rd_regs(priv, reg, val, 1);
+}
- if (i2c_transfer(state->i2c, msg, 2) != 2) {
- warn("I2C read failed reg:%04x", reg);
- return -EREMOTEIO;
- }
- *val = ibuf[0];
- return 0;
+static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val,
+ u8 len)
+{
+ u8 mbox = (1 << 7)|(1 << 6)|((len - 1) << 2)|(1 << 1)|(1 << 0);
+ return af9013_wr_regs_i2c(state, mbox, reg, val, len);
}
-static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos,
- u8 len, u8 val)
+static int af9013_wr_reg_bits(struct af9013_state *state, u16 reg, int pos,
+ int len, u8 val)
{
int ret;
u8 tmp, mask;
- ret = af9013_read_reg(state, reg, &tmp);
- if (ret)
- return ret;
+ /* no need for read if whole reg is written */
+ if (len != 8) {
+ ret = af9013_rd_reg(state, reg, &tmp);
+ if (ret)
+ return ret;
- mask = regmask[len - 1] << pos;
- tmp = (tmp & ~mask) | ((val << pos) & mask);
+ mask = (0xff >> (8 - len)) << pos;
+ val <<= pos;
+ tmp &= ~mask;
+ val |= tmp;
+ }
- return af9013_write_reg(state, reg, tmp);
+ return af9013_wr_reg(state, reg, val);
}
-static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos,
- u8 len, u8 *val)
+static int af9013_rd_reg_bits(struct af9013_state *state, u16 reg, int pos,
+ int len, u8 *val)
{
int ret;
u8 tmp;
- ret = af9013_read_reg(state, reg, &tmp);
+ ret = af9013_rd_reg(state, reg, &tmp);
if (ret)
return ret;
- *val = (tmp >> pos) & regmask[len - 1];
+
+ *val = (tmp >> pos);
+ *val &= (0xff >> (8 - len));
+
return 0;
}
@@ -157,10 +219,13 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
int ret;
u8 pos;
u16 addr;
- deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval);
-/* GPIO0 & GPIO1 0xd735
- GPIO2 & GPIO3 0xd736 */
+ dbg("%s: gpio=%d gpioval=%02x", __func__, gpio, gpioval);
+
+ /*
+ * GPIO0 & GPIO1 0xd735
+ * GPIO2 & GPIO3 0xd736
+ */
switch (gpio) {
case 0:
@@ -175,7 +240,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
default:
err("invalid gpio:%d\n", gpio);
ret = -EINVAL;
- goto error;
+ goto err;
};
switch (gpio) {
@@ -190,16 +255,21 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
break;
};
- ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval);
+ ret = af9013_wr_reg_bits(state, addr, pos, 4, gpioval);
+ if (ret)
+ goto err;
-error:
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
return ret;
}
static u32 af913_div(u32 a, u32 b, u32 x)
{
u32 r = 0, c = 0, i;
- deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x);
+
+ dbg("%s: a=%d b=%d x=%d", __func__, a, b, x);
if (a > b) {
c = a / b;
@@ -216,205 +286,407 @@ static u32 af913_div(u32 a, u32 b, u32 x)
}
r = (c << (u32)x) + r;
- deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r);
+ dbg("%s: a=%d b=%d x=%d r=%x", __func__, a, b, x, r);
return r;
}
-static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
+static int af9013_power_ctrl(struct af9013_state *state, u8 onoff)
{
- int ret, i, j, found;
- deb_info("%s: adc_clock:%d bw:%d\n", __func__,
- state->config.adc_clock, bw);
-
- /* lookup coeff from table */
- for (i = 0, found = 0; i < ARRAY_SIZE(coeff_table); i++) {
- if (coeff_table[i].adc_clock == state->config.adc_clock &&
- coeff_table[i].bw == bw) {
- found = 1;
- break;
- }
- }
+ int ret, i;
+ u8 tmp;
- if (!found) {
- err("invalid bw or clock");
- ret = -EINVAL;
- goto error;
+ dbg("%s: onoff=%d", __func__, onoff);
+
+ /* enable reset */
+ ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 1);
+ if (ret)
+ goto err;
+
+ /* start reset mechanism */
+ ret = af9013_wr_reg(state, 0xaeff, 1);
+ if (ret)
+ goto err;
+
+ /* wait reset performs */
+ for (i = 0; i < 150; i++) {
+ ret = af9013_rd_reg_bits(state, 0xd417, 1, 1, &tmp);
+ if (ret)
+ goto err;
+
+ if (tmp)
+ break; /* reset done */
+
+ usleep_range(5000, 25000);
}
- deb_info("%s: coeff: ", __func__);
- debug_dump(coeff_table[i].val, sizeof(coeff_table[i].val), deb_info);
+ if (!tmp)
+ return -ETIMEDOUT;
- /* program */
- for (j = 0; j < sizeof(coeff_table[i].val); j++) {
- ret = af9013_write_reg(state, 0xae00 + j,
- coeff_table[i].val[j]);
+ if (onoff) {
+ /* clear reset */
+ ret = af9013_wr_reg_bits(state, 0xd417, 1, 1, 0);
if (ret)
- break;
+ goto err;
+
+ /* disable reset */
+ ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 0);
+
+ /* power on */
+ ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 0);
+ } else {
+ /* power off */
+ ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 1);
}
-error:
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe)
+{
+ struct af9013_state *state = fe->demodulator_priv;
+ int ret;
+
+ dbg("%s", __func__);
+
+ /* reset and start BER counter */
+ ret = af9013_wr_reg_bits(state, 0xd391, 4, 1, 1);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
return ret;
}
-static int af9013_set_adc_ctrl(struct af9013_state *state)
+static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe)
{
+ struct af9013_state *state = fe->demodulator_priv;
int ret;
- u8 buf[3], tmp, i;
- u32 adc_cw;
+ u8 buf[5];
- deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock);
+ dbg("%s", __func__);
- /* adc frequency type */
- switch (state->config.adc_clock) {
- case 28800: /* 28.800 MHz */
- tmp = 0;
- break;
- case 20480: /* 20.480 MHz */
- tmp = 1;
+ /* check if error bit count is ready */
+ ret = af9013_rd_reg_bits(state, 0xd391, 4, 1, &buf[0]);
+ if (ret)
+ goto err;
+
+ if (!buf[0]) {
+ dbg("%s: not ready", __func__);
+ return 0;
+ }
+
+ ret = af9013_rd_regs(state, 0xd387, buf, 5);
+ if (ret)
+ goto err;
+
+ state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ state->ucblocks += (buf[4] << 8) | buf[3];
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int af9013_statistics_snr_start(struct dvb_frontend *fe)
+{
+ struct af9013_state *state = fe->demodulator_priv;
+ int ret;
+
+ dbg("%s", __func__);
+
+ /* start SNR meas */
+ ret = af9013_wr_reg_bits(state, 0xd2e1, 3, 1, 1);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int af9013_statistics_snr_result(struct dvb_frontend *fe)
+{
+ struct af9013_state *state = fe->demodulator_priv;
+ int ret, i, len;
+ u8 buf[3], tmp;
+ u32 snr_val;
+ const struct af9013_snr *uninitialized_var(snr_lut);
+
+ dbg("%s", __func__);
+
+ /* check if SNR ready */
+ ret = af9013_rd_reg_bits(state, 0xd2e1, 3, 1, &tmp);
+ if (ret)
+ goto err;
+
+ if (!tmp) {
+ dbg("%s: not ready", __func__);
+ return 0;
+ }
+
+ /* read value */
+ ret = af9013_rd_regs(state, 0xd2e3, buf, 3);
+ if (ret)
+ goto err;
+
+ snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+ /* read current modulation */
+ ret = af9013_rd_reg(state, 0xd3c1, &tmp);
+ if (ret)
+ goto err;
+
+ switch ((tmp >> 6) & 3) {
+ case 0:
+ len = ARRAY_SIZE(qpsk_snr_lut);
+ snr_lut = qpsk_snr_lut;
break;
- case 28000: /* 28.000 MHz */
- tmp = 2;
+ case 1:
+ len = ARRAY_SIZE(qam16_snr_lut);
+ snr_lut = qam16_snr_lut;
break;
- case 25000: /* 25.000 MHz */
- tmp = 3;
+ case 2:
+ len = ARRAY_SIZE(qam64_snr_lut);
+ snr_lut = qam64_snr_lut;
break;
default:
- err("invalid xtal");
- return -EINVAL;
+ goto err;
+ break;
}
- adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul);
+ for (i = 0; i < len; i++) {
+ tmp = snr_lut[i].snr;
- buf[0] = (u8) ((adc_cw & 0x000000ff));
- buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8);
- buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16);
+ if (snr_val < snr_lut[i].val)
+ break;
+ }
+ state->snr = tmp * 10; /* dB/10 */
- deb_info("%s: adc_cw:", __func__);
- debug_dump(buf, sizeof(buf), deb_info);
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int af9013_statistics_signal_strength(struct dvb_frontend *fe)
+{
+ struct af9013_state *state = fe->demodulator_priv;
+ int ret = 0;
+ u8 buf[2], rf_gain, if_gain;
+ int signal_strength;
+
+ dbg("%s", __func__);
+
+ if (!state->signal_strength_en)
+ return 0;
+
+ ret = af9013_rd_regs(state, 0xd07c, buf, 2);
+ if (ret)
+ goto err;
+
+ rf_gain = buf[0];
+ if_gain = buf[1];
+
+ signal_strength = (0xffff / \
+ (9 * (state->rf_50 + state->if_50) - \
+ 11 * (state->rf_80 + state->if_80))) * \
+ (10 * (rf_gain + if_gain) - \
+ 11 * (state->rf_80 + state->if_80));
+ if (signal_strength < 0)
+ signal_strength = 0;
+ else if (signal_strength > 0xffff)
+ signal_strength = 0xffff;
+
+ state->signal_strength = signal_strength;
- /* program */
- for (i = 0; i < sizeof(buf); i++) {
- ret = af9013_write_reg(state, 0xd180 + i, buf[i]);
- if (ret)
- goto error;
- }
- ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp);
-error:
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
return ret;
}
-static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw)
+static void af9013_statistics_work(struct work_struct *work)
{
int ret;
- u16 addr;
- u8 buf[3], i, j;
- u32 adc_freq, freq_cw;
- s8 bfs_spec_inv;
- int if_sample_freq;
-
- for (j = 0; j < 3; j++) {
- if (j == 0) {
- addr = 0xd140; /* fcw normal */
- bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1;
- } else if (j == 1) {
- addr = 0x9be7; /* fcw dummy ram */
- bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1;
- } else {
- addr = 0x9bea; /* fcw inverted */
- bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1;
- }
+ struct af9013_state *state = container_of(work,
+ struct af9013_state, statistics_work.work);
+ unsigned int next_msec;
+
+ /* update only signal strength when demod is not locked */
+ if (!(state->fe_status & FE_HAS_LOCK)) {
+ state->statistics_step = 0;
+ state->ber = 0;
+ state->snr = 0;
+ }
+
+ switch (state->statistics_step) {
+ default:
+ state->statistics_step = 0;
+ case 0:
+ ret = af9013_statistics_signal_strength(&state->fe);
+ state->statistics_step++;
+ next_msec = 300;
+ break;
+ case 1:
+ ret = af9013_statistics_snr_start(&state->fe);
+ state->statistics_step++;
+ next_msec = 200;
+ break;
+ case 2:
+ ret = af9013_statistics_ber_unc_start(&state->fe);
+ state->statistics_step++;
+ next_msec = 1000;
+ break;
+ case 3:
+ ret = af9013_statistics_snr_result(&state->fe);
+ state->statistics_step++;
+ next_msec = 400;
+ break;
+ case 4:
+ ret = af9013_statistics_ber_unc_result(&state->fe);
+ state->statistics_step++;
+ next_msec = 100;
+ break;
+ }
- adc_freq = state->config.adc_clock * 1000;
- if_sample_freq = state->config.tuner_if * 1000;
+ schedule_delayed_work(&state->statistics_work,
+ msecs_to_jiffies(next_msec));
- /* TDA18271 uses different sampling freq for every bw */
- if (state->config.tuner == AF9013_TUNER_TDA18271) {
- switch (bw) {
- case BANDWIDTH_6_MHZ:
- if_sample_freq = 3300000; /* 3.3 MHz */
- break;
- case BANDWIDTH_7_MHZ:
- if_sample_freq = 3500000; /* 3.5 MHz */
- break;
- case BANDWIDTH_8_MHZ:
- default:
- if_sample_freq = 4000000; /* 4.0 MHz */
- break;
- }
- } else if (state->config.tuner == AF9013_TUNER_TDA18218) {
- switch (bw) {
- case BANDWIDTH_6_MHZ:
- if_sample_freq = 3000000; /* 3 MHz */
- break;
- case BANDWIDTH_7_MHZ:
- if_sample_freq = 3500000; /* 3.5 MHz */
- break;
- case BANDWIDTH_8_MHZ:
- default:
- if_sample_freq = 4000000; /* 4 MHz */
+ return;
+}
+
+static int af9013_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *fesettings)
+{
+ fesettings->min_delay_ms = 800;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+
+ return 0;
+}
+
+static int af9013_set_frontend(struct dvb_frontend *fe)
+{
+ struct af9013_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i, sampling_freq;
+ bool auto_mode, spec_inv;
+ u8 buf[6];
+ u32 if_frequency, freq_cw;
+
+ dbg("%s: frequency=%d bandwidth_hz=%d", __func__,
+ c->frequency, c->bandwidth_hz);
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe);
+
+ /* program CFOE coefficients */
+ if (c->bandwidth_hz != state->bandwidth_hz) {
+ for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
+ if (coeff_lut[i].clock == state->config.clock &&
+ coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
break;
}
}
- while (if_sample_freq > (adc_freq / 2))
- if_sample_freq = if_sample_freq - adc_freq;
+ ret = af9013_wr_regs(state, 0xae00, coeff_lut[i].val,
+ sizeof(coeff_lut[i].val));
+ }
- if (if_sample_freq >= 0)
- bfs_spec_inv = bfs_spec_inv * (-1);
+ /* program frequency control */
+ if (c->bandwidth_hz != state->bandwidth_hz || state->first_tune) {
+ /* get used IF frequency */
+ if (fe->ops.tuner_ops.get_if_frequency)
+ fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
else
- if_sample_freq = if_sample_freq * (-1);
+ if_frequency = state->config.if_frequency;
+
+ sampling_freq = if_frequency;
- freq_cw = af913_div(if_sample_freq, adc_freq, 23ul);
+ while (sampling_freq > (state->config.clock / 2))
+ sampling_freq -= state->config.clock;
- if (bfs_spec_inv == -1)
- freq_cw = 0x00800000 - freq_cw;
+ if (sampling_freq < 0) {
+ sampling_freq *= -1;
+ spec_inv = state->config.spec_inv;
+ } else {
+ spec_inv = !state->config.spec_inv;
+ }
- buf[0] = (u8) ((freq_cw & 0x000000ff));
- buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8);
- buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16);
+ freq_cw = af913_div(sampling_freq, state->config.clock, 23);
+ if (spec_inv)
+ freq_cw = 0x800000 - freq_cw;
- deb_info("%s: freq_cw:", __func__);
- debug_dump(buf, sizeof(buf), deb_info);
+ buf[0] = (freq_cw >> 0) & 0xff;
+ buf[1] = (freq_cw >> 8) & 0xff;
+ buf[2] = (freq_cw >> 16) & 0x7f;
- /* program */
- for (i = 0; i < sizeof(buf); i++) {
- ret = af9013_write_reg(state, addr++, buf[i]);
- if (ret)
- goto error;
- }
+ freq_cw = 0x800000 - freq_cw;
+
+ buf[3] = (freq_cw >> 0) & 0xff;
+ buf[4] = (freq_cw >> 8) & 0xff;
+ buf[5] = (freq_cw >> 16) & 0x7f;
+
+ ret = af9013_wr_regs(state, 0xd140, buf, 3);
+ if (ret)
+ goto err;
+
+ ret = af9013_wr_regs(state, 0x9be7, buf, 6);
+ if (ret)
+ goto err;
}
-error:
- return ret;
-}
-static int af9013_set_ofdm_params(struct af9013_state *state,
- struct dvb_ofdm_parameters *params, u8 *auto_mode)
-{
- int ret;
- u8 i, buf[3] = {0, 0, 0};
- *auto_mode = 0; /* set if parameters are requested to auto set */
+ /* clear TPS lock flag */
+ ret = af9013_wr_reg_bits(state, 0xd330, 3, 1, 1);
+ if (ret)
+ goto err;
+
+ /* clear MPEG2 lock flag */
+ ret = af9013_wr_reg_bits(state, 0xd507, 6, 1, 0);
+ if (ret)
+ goto err;
+
+ /* empty channel function */
+ ret = af9013_wr_reg_bits(state, 0x9bfe, 0, 1, 0);
+ if (ret)
+ goto err;
- /* Try auto-detect transmission parameters in case of AUTO requested or
- garbage parameters given by application for compatibility.
- MPlayer seems to provide garbage parameters currently. */
+ /* empty DVB-T channel function */
+ ret = af9013_wr_reg_bits(state, 0x9bc2, 0, 1, 0);
+ if (ret)
+ goto err;
+
+ /* transmission parameters */
+ auto_mode = false;
+ memset(buf, 0, 3);
- switch (params->transmission_mode) {
+ switch (c->transmission_mode) {
case TRANSMISSION_MODE_AUTO:
- *auto_mode = 1;
+ auto_mode = 1;
+ break;
case TRANSMISSION_MODE_2K:
break;
case TRANSMISSION_MODE_8K:
buf[0] |= (1 << 0);
break;
default:
- deb_info("%s: invalid transmission_mode\n", __func__);
- *auto_mode = 1;
+ dbg("%s: invalid transmission_mode", __func__);
+ auto_mode = 1;
}
- switch (params->guard_interval) {
+ switch (c->guard_interval) {
case GUARD_INTERVAL_AUTO:
- *auto_mode = 1;
+ auto_mode = 1;
+ break;
case GUARD_INTERVAL_1_32:
break;
case GUARD_INTERVAL_1_16:
@@ -427,13 +699,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[0] |= (3 << 2);
break;
default:
- deb_info("%s: invalid guard_interval\n", __func__);
- *auto_mode = 1;
+ dbg("%s: invalid guard_interval", __func__);
+ auto_mode = 1;
}
- switch (params->hierarchy_information) {
+ switch (c->hierarchy) {
case HIERARCHY_AUTO:
- *auto_mode = 1;
+ auto_mode = 1;
+ break;
case HIERARCHY_NONE:
break;
case HIERARCHY_1:
@@ -446,13 +719,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[0] |= (3 << 4);
break;
default:
- deb_info("%s: invalid hierarchy_information\n", __func__);
- *auto_mode = 1;
+ dbg("%s: invalid hierarchy", __func__);
+ auto_mode = 1;
};
- switch (params->constellation) {
+ switch (c->modulation) {
case QAM_AUTO:
- *auto_mode = 1;
+ auto_mode = 1;
+ break;
case QPSK:
break;
case QAM_16:
@@ -462,16 +736,17 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[1] |= (2 << 6);
break;
default:
- deb_info("%s: invalid constellation\n", __func__);
- *auto_mode = 1;
+ dbg("%s: invalid modulation", __func__);
+ auto_mode = 1;
}
/* Use HP. How and which case we can switch to LP? */
buf[1] |= (1 << 4);
- switch (params->code_rate_HP) {
+ switch (c->code_rate_HP) {
case FEC_AUTO:
- *auto_mode = 1;
+ auto_mode = 1;
+ break;
case FEC_1_2:
break;
case FEC_2_3:
@@ -487,16 +762,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[2] |= (4 << 0);
break;
default:
- deb_info("%s: invalid code_rate_HP\n", __func__);
- *auto_mode = 1;
+ dbg("%s: invalid code_rate_HP", __func__);
+ auto_mode = 1;
}
- switch (params->code_rate_LP) {
+ switch (c->code_rate_LP) {
case FEC_AUTO:
- /* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO
- by dvb_frontend.c for compatibility */
- if (params->hierarchy_information != HIERARCHY_NONE)
- *auto_mode = 1;
+ auto_mode = 1;
+ break;
case FEC_1_2:
break;
case FEC_2_3:
@@ -512,709 +785,373 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[2] |= (4 << 3);
break;
case FEC_NONE:
- if (params->hierarchy_information == HIERARCHY_AUTO)
- break;
+ break;
default:
- deb_info("%s: invalid code_rate_LP\n", __func__);
- *auto_mode = 1;
+ dbg("%s: invalid code_rate_LP", __func__);
+ auto_mode = 1;
}
- switch (params->bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (c->bandwidth_hz) {
+ case 6000000:
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
buf[1] |= (1 << 2);
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
buf[1] |= (2 << 2);
break;
default:
- deb_info("%s: invalid bandwidth\n", __func__);
- buf[1] |= (2 << 2); /* cannot auto-detect BW, try 8 MHz */
- }
-
- /* program */
- for (i = 0; i < sizeof(buf); i++) {
- ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]);
- if (ret)
- break;
+ dbg("%s: invalid bandwidth_hz", __func__);
+ ret = -EINVAL;
+ goto err;
}
- return ret;
-}
-
-static int af9013_reset(struct af9013_state *state, u8 sleep)
-{
- int ret;
- u8 tmp, i;
- deb_info("%s\n", __func__);
-
- /* enable OFDM reset */
- ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1);
- if (ret)
- goto error;
-
- /* start reset mechanism */
- ret = af9013_write_reg(state, 0xaeff, 1);
+ ret = af9013_wr_regs(state, 0xd3c0, buf, 3);
if (ret)
- goto error;
+ goto err;
- /* reset is done when bit 1 is set */
- for (i = 0; i < 150; i++) {
- ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp);
- if (ret)
- goto error;
- if (tmp)
- break; /* reset done */
- msleep(10);
- }
- if (!tmp)
- return -ETIMEDOUT;
-
- /* don't clear reset when going to sleep */
- if (!sleep) {
- /* clear OFDM reset */
- ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0);
+ if (auto_mode) {
+ /* clear easy mode flag */
+ ret = af9013_wr_reg(state, 0xaefd, 0);
if (ret)
- goto error;
-
- /* disable OFDM reset */
- ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0);
- }
-error:
- return ret;
-}
-
-static int af9013_power_ctrl(struct af9013_state *state, u8 onoff)
-{
- int ret;
- deb_info("%s: onoff:%d\n", __func__, onoff);
+ goto err;
- if (onoff) {
- /* power on */
- ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0);
- if (ret)
- goto error;
- ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0);
- if (ret)
- goto error;
- ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0);
+ dbg("%s: auto params", __func__);
} else {
- /* power off */
- ret = af9013_reset(state, 1);
+ /* set easy mode flag */
+ ret = af9013_wr_reg(state, 0xaefd, 1);
if (ret)
- goto error;
- ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1);
- }
-error:
- return ret;
-}
-
-static int af9013_lock_led(struct af9013_state *state, u8 onoff)
-{
- deb_info("%s: onoff:%d\n", __func__, onoff);
-
- return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff);
-}
-
-static int af9013_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- struct af9013_state *state = fe->demodulator_priv;
- int ret;
- u8 auto_mode; /* auto set TPS */
+ goto err;
- deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency,
- params->u.ofdm.bandwidth);
-
- state->frequency = params->frequency;
-
- /* program tuner */
- if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, params);
-
- /* program CFOE coefficients */
- ret = af9013_set_coeff(state, params->u.ofdm.bandwidth);
- if (ret)
- goto error;
-
- /* program frequency control */
- ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth);
- if (ret)
- goto error;
-
- /* clear TPS lock flag (inverted flag) */
- ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1);
- if (ret)
- goto error;
-
- /* clear MPEG2 lock flag */
- ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0);
- if (ret)
- goto error;
-
- /* empty channel function */
- ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0);
- if (ret)
- goto error;
-
- /* empty DVB-T channel function */
- ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0);
- if (ret)
- goto error;
-
- /* program TPS and bandwidth, check if auto mode needed */
- ret = af9013_set_ofdm_params(state, &params->u.ofdm, &auto_mode);
- if (ret)
- goto error;
-
- if (auto_mode) {
- /* clear easy mode flag */
- ret = af9013_write_reg(state, 0xaefd, 0);
- deb_info("%s: auto TPS\n", __func__);
- } else {
- /* set easy mode flag */
- ret = af9013_write_reg(state, 0xaefd, 1);
+ ret = af9013_wr_reg(state, 0xaefe, 0);
if (ret)
- goto error;
- ret = af9013_write_reg(state, 0xaefe, 0);
- deb_info("%s: manual TPS\n", __func__);
+ goto err;
+
+ dbg("%s: manual params", __func__);
}
- if (ret)
- goto error;
- /* everything is set, lets try to receive channel - OFSM GO! */
- ret = af9013_write_reg(state, 0xffff, 0);
+ /* tune */
+ ret = af9013_wr_reg(state, 0xffff, 0);
if (ret)
- goto error;
+ goto err;
+
+ state->bandwidth_hz = c->bandwidth_hz;
+ state->set_frontend_jiffies = jiffies;
+ state->first_tune = false;
-error:
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
return ret;
}
-static int af9013_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int af9013_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct af9013_state *state = fe->demodulator_priv;
int ret;
- u8 i, buf[3];
- deb_info("%s\n", __func__);
+ u8 buf[3];
- /* read TPS registers */
- for (i = 0; i < 3; i++) {
- ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]);
- if (ret)
- goto error;
- }
+ dbg("%s", __func__);
+
+ ret = af9013_rd_regs(state, 0xd3c0, buf, 3);
+ if (ret)
+ goto err;
switch ((buf[1] >> 6) & 3) {
case 0:
- p->u.ofdm.constellation = QPSK;
+ c->modulation = QPSK;
break;
case 1:
- p->u.ofdm.constellation = QAM_16;
+ c->modulation = QAM_16;
break;
case 2:
- p->u.ofdm.constellation = QAM_64;
+ c->modulation = QAM_64;
break;
}
switch ((buf[0] >> 0) & 3) {
case 0:
- p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+ c->transmission_mode = TRANSMISSION_MODE_2K;
break;
case 1:
- p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ c->transmission_mode = TRANSMISSION_MODE_8K;
}
switch ((buf[0] >> 2) & 3) {
case 0:
- p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ c->guard_interval = GUARD_INTERVAL_1_32;
break;
case 1:
- p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+ c->guard_interval = GUARD_INTERVAL_1_16;
break;
case 2:
- p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+ c->guard_interval = GUARD_INTERVAL_1_8;
break;
case 3:
- p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+ c->guard_interval = GUARD_INTERVAL_1_4;
break;
}
switch ((buf[0] >> 4) & 7) {
case 0:
- p->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ c->hierarchy = HIERARCHY_NONE;
break;
case 1:
- p->u.ofdm.hierarchy_information = HIERARCHY_1;
+ c->hierarchy = HIERARCHY_1;
break;
case 2:
- p->u.ofdm.hierarchy_information = HIERARCHY_2;
+ c->hierarchy = HIERARCHY_2;
break;
case 3:
- p->u.ofdm.hierarchy_information = HIERARCHY_4;
+ c->hierarchy = HIERARCHY_4;
break;
}
switch ((buf[2] >> 0) & 7) {
case 0:
- p->u.ofdm.code_rate_HP = FEC_1_2;
+ c->code_rate_HP = FEC_1_2;
break;
case 1:
- p->u.ofdm.code_rate_HP = FEC_2_3;
+ c->code_rate_HP = FEC_2_3;
break;
case 2:
- p->u.ofdm.code_rate_HP = FEC_3_4;
+ c->code_rate_HP = FEC_3_4;
break;
case 3:
- p->u.ofdm.code_rate_HP = FEC_5_6;
+ c->code_rate_HP = FEC_5_6;
break;
case 4:
- p->u.ofdm.code_rate_HP = FEC_7_8;
+ c->code_rate_HP = FEC_7_8;
break;
}
switch ((buf[2] >> 3) & 7) {
case 0:
- p->u.ofdm.code_rate_LP = FEC_1_2;
+ c->code_rate_LP = FEC_1_2;
break;
case 1:
- p->u.ofdm.code_rate_LP = FEC_2_3;
+ c->code_rate_LP = FEC_2_3;
break;
case 2:
- p->u.ofdm.code_rate_LP = FEC_3_4;
+ c->code_rate_LP = FEC_3_4;
break;
case 3:
- p->u.ofdm.code_rate_LP = FEC_5_6;
+ c->code_rate_LP = FEC_5_6;
break;
case 4:
- p->u.ofdm.code_rate_LP = FEC_7_8;
+ c->code_rate_LP = FEC_7_8;
break;
}
switch ((buf[1] >> 2) & 3) {
case 0:
- p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ c->bandwidth_hz = 6000000;
break;
case 1:
- p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ c->bandwidth_hz = 7000000;
break;
case 2:
- p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ c->bandwidth_hz = 8000000;
break;
}
- p->inversion = INVERSION_AUTO;
- p->frequency = state->frequency;
-
-error:
return ret;
-}
-
-static int af9013_update_ber_unc(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- int ret;
- u8 buf[3], i;
- u32 error_bit_count = 0;
- u32 total_bit_count = 0;
- u32 abort_packet_count = 0;
-
- state->ber = 0;
-
- /* check if error bit count is ready */
- ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]);
- if (ret)
- goto error;
- if (!buf[0])
- goto exit;
-
- /* get RSD packet abort count */
- for (i = 0; i < 2; i++) {
- ret = af9013_read_reg(state, 0xd38a + i, &buf[i]);
- if (ret)
- goto error;
- }
- abort_packet_count = (buf[1] << 8) + buf[0];
-
- /* get error bit count */
- for (i = 0; i < 3; i++) {
- ret = af9013_read_reg(state, 0xd387 + i, &buf[i]);
- if (ret)
- goto error;
- }
- error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0];
- error_bit_count = error_bit_count - abort_packet_count * 8 * 8;
-
- /* get used RSD counting period (10000 RSD packets used) */
- for (i = 0; i < 2; i++) {
- ret = af9013_read_reg(state, 0xd385 + i, &buf[i]);
- if (ret)
- goto error;
- }
- total_bit_count = (buf[1] << 8) + buf[0];
- total_bit_count = total_bit_count - abort_packet_count;
- total_bit_count = total_bit_count * 204 * 8;
-
- if (total_bit_count)
- state->ber = error_bit_count * 1000000000 / total_bit_count;
-
- state->ucblocks += abort_packet_count;
-
- deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__,
- error_bit_count, total_bit_count, abort_packet_count);
-
- /* set BER counting range */
- ret = af9013_write_reg(state, 0xd385, 10000 & 0xff);
- if (ret)
- goto error;
- ret = af9013_write_reg(state, 0xd386, 10000 >> 8);
- if (ret)
- goto error;
- /* reset and start BER counter */
- ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1);
- if (ret)
- goto error;
-
-exit:
-error:
+err:
+ dbg("%s: failed=%d", __func__, ret);
return ret;
}
-static int af9013_update_snr(struct dvb_frontend *fe)
+static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct af9013_state *state = fe->demodulator_priv;
int ret;
- u8 buf[3], i, len;
- u32 quant = 0;
- struct snr_table *uninitialized_var(snr_table);
-
- /* check if quantizer ready (for snr) */
- ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]);
- if (ret)
- goto error;
- if (buf[0]) {
- /* quantizer ready - read it */
- for (i = 0; i < 3; i++) {
- ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]);
- if (ret)
- goto error;
- }
- quant = (buf[2] << 16) + (buf[1] << 8) + buf[0];
-
- /* read current constellation */
- ret = af9013_read_reg(state, 0xd3c1, &buf[0]);
- if (ret)
- goto error;
-
- switch ((buf[0] >> 6) & 3) {
- case 0:
- len = ARRAY_SIZE(qpsk_snr_table);
- snr_table = qpsk_snr_table;
- break;
- case 1:
- len = ARRAY_SIZE(qam16_snr_table);
- snr_table = qam16_snr_table;
- break;
- case 2:
- len = ARRAY_SIZE(qam64_snr_table);
- snr_table = qam64_snr_table;
- break;
- default:
- len = 0;
- break;
- }
-
- if (len) {
- for (i = 0; i < len; i++) {
- if (quant < snr_table[i].val) {
- state->snr = snr_table[i].snr * 10;
- break;
- }
- }
- }
-
- /* set quantizer super frame count */
- ret = af9013_write_reg(state, 0xd2e2, 1);
- if (ret)
- goto error;
-
- /* check quantizer availability */
- for (i = 0; i < 10; i++) {
- msleep(10);
- ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1,
- &buf[0]);
- if (ret)
- goto error;
- if (!buf[0])
- break;
- }
-
- /* reset quantizer */
- ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1);
- if (ret)
- goto error;
- }
-
-error:
- return ret;
-}
-
-static int af9013_update_signal_strength(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- int ret = 0;
- u8 rf_gain, if_gain;
- int signal_strength;
-
- deb_info("%s\n", __func__);
+ u8 tmp;
- if (state->signal_strength_en) {
- ret = af9013_read_reg(state, 0xd07c, &rf_gain);
- if (ret)
- goto error;
- ret = af9013_read_reg(state, 0xd07d, &if_gain);
- if (ret)
- goto error;
- signal_strength = (0xffff / \
- (9 * (state->rf_50 + state->if_50) - \
- 11 * (state->rf_80 + state->if_80))) * \
- (10 * (rf_gain + if_gain) - \
- 11 * (state->rf_80 + state->if_80));
- if (signal_strength < 0)
- signal_strength = 0;
- else if (signal_strength > 0xffff)
- signal_strength = 0xffff;
-
- state->signal_strength = signal_strength;
+ /*
+ * Return status from the cache if it is younger than 2000ms with the
+ * exception of last tune is done during 4000ms.
+ */
+ if (time_is_after_jiffies(
+ state->read_status_jiffies + msecs_to_jiffies(2000)) &&
+ time_is_before_jiffies(
+ state->set_frontend_jiffies + msecs_to_jiffies(4000))
+ ) {
+ *status = state->fe_status;
+ return 0;
} else {
- state->signal_strength = 0;
+ *status = 0;
}
-error:
- return ret;
-}
-
-static int af9013_update_statistics(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- int ret;
-
- if (time_before(jiffies, state->next_statistics_check))
- return 0;
-
- /* set minimum statistic update interval */
- state->next_statistics_check = jiffies + msecs_to_jiffies(1200);
-
- ret = af9013_update_signal_strength(fe);
- if (ret)
- goto error;
- ret = af9013_update_snr(fe);
- if (ret)
- goto error;
- ret = af9013_update_ber_unc(fe);
- if (ret)
- goto error;
-
-error:
- return ret;
-}
-
-static int af9013_get_tune_settings(struct dvb_frontend *fe,
- struct dvb_frontend_tune_settings *fesettings)
-{
- fesettings->min_delay_ms = 800;
- fesettings->step_size = 0;
- fesettings->max_drift = 0;
-
- return 0;
-}
-
-static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct af9013_state *state = fe->demodulator_priv;
- int ret = 0;
- u8 tmp;
- *status = 0;
-
/* MPEG2 lock */
- ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp);
+ ret = af9013_rd_reg_bits(state, 0xd507, 6, 1, &tmp);
if (ret)
- goto error;
+ goto err;
+
if (tmp)
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
FE_HAS_SYNC | FE_HAS_LOCK;
if (!*status) {
/* TPS lock */
- ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
+ ret = af9013_rd_reg_bits(state, 0xd330, 3, 1, &tmp);
if (ret)
- goto error;
+ goto err;
+
if (tmp)
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI;
}
- if (!*status) {
- /* CFO lock */
- ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp);
- if (ret)
- goto error;
- if (tmp)
- *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
- }
-
- if (!*status) {
- /* SFOE lock */
- ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp);
- if (ret)
- goto error;
- if (tmp)
- *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
- }
+ state->fe_status = *status;
+ state->read_status_jiffies = jiffies;
- if (!*status) {
- /* AGC lock */
- ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
- if (ret)
- goto error;
- if (tmp)
- *status |= FE_HAS_SIGNAL;
- }
-
- ret = af9013_update_statistics(fe);
-
-error:
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
return ret;
}
-
-static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber)
+static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct af9013_state *state = fe->demodulator_priv;
- int ret;
- ret = af9013_update_statistics(fe);
- *ber = state->ber;
- return ret;
+ *snr = state->snr;
+ return 0;
}
static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
struct af9013_state *state = fe->demodulator_priv;
- int ret;
- ret = af9013_update_statistics(fe);
*strength = state->signal_strength;
- return ret;
+ return 0;
}
-static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr)
+static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct af9013_state *state = fe->demodulator_priv;
- int ret;
- ret = af9013_update_statistics(fe);
- *snr = state->snr;
- return ret;
+ *ber = state->ber;
+ return 0;
}
static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
struct af9013_state *state = fe->demodulator_priv;
- int ret;
- ret = af9013_update_statistics(fe);
*ucblocks = state->ucblocks;
- return ret;
-}
-
-static int af9013_sleep(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- int ret;
- deb_info("%s\n", __func__);
-
- ret = af9013_lock_led(state, 0);
- if (ret)
- goto error;
-
- ret = af9013_power_ctrl(state, 0);
-error:
- return ret;
+ return 0;
}
static int af9013_init(struct dvb_frontend *fe)
{
struct af9013_state *state = fe->demodulator_priv;
int ret, i, len;
- u8 tmp0, tmp1;
- struct regdesc *init;
- deb_info("%s\n", __func__);
+ u8 buf[3], tmp;
+ u32 adc_cw;
+ const struct af9013_reg_bit *init;
- /* reset OFDM */
- ret = af9013_reset(state, 0);
- if (ret)
- goto error;
+ dbg("%s", __func__);
/* power on */
ret = af9013_power_ctrl(state, 1);
if (ret)
- goto error;
+ goto err;
/* enable ADC */
- ret = af9013_write_reg(state, 0xd73a, 0xa4);
+ ret = af9013_wr_reg(state, 0xd73a, 0xa4);
if (ret)
- goto error;
+ goto err;
/* write API version to firmware */
- for (i = 0; i < sizeof(state->config.api_version); i++) {
- ret = af9013_write_reg(state, 0x9bf2 + i,
- state->config.api_version[i]);
- if (ret)
- goto error;
- }
+ ret = af9013_wr_regs(state, 0x9bf2, state->config.api_version, 4);
+ if (ret)
+ goto err;
/* program ADC control */
- ret = af9013_set_adc_ctrl(state);
+ switch (state->config.clock) {
+ case 28800000: /* 28.800 MHz */
+ tmp = 0;
+ break;
+ case 20480000: /* 20.480 MHz */
+ tmp = 1;
+ break;
+ case 28000000: /* 28.000 MHz */
+ tmp = 2;
+ break;
+ case 25000000: /* 25.000 MHz */
+ tmp = 3;
+ break;
+ default:
+ err("invalid clock");
+ return -EINVAL;
+ }
+
+ adc_cw = af913_div(state->config.clock, 1000000ul, 19);
+ buf[0] = (adc_cw >> 0) & 0xff;
+ buf[1] = (adc_cw >> 8) & 0xff;
+ buf[2] = (adc_cw >> 16) & 0xff;
+
+ ret = af9013_wr_regs(state, 0xd180, buf, 3);
+ if (ret)
+ goto err;
+
+ ret = af9013_wr_reg_bits(state, 0x9bd2, 0, 4, tmp);
if (ret)
- goto error;
+ goto err;
/* set I2C master clock */
- ret = af9013_write_reg(state, 0xd416, 0x14);
+ ret = af9013_wr_reg(state, 0xd416, 0x14);
if (ret)
- goto error;
+ goto err;
/* set 16 embx */
- ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1);
+ ret = af9013_wr_reg_bits(state, 0xd700, 1, 1, 1);
if (ret)
- goto error;
+ goto err;
/* set no trigger */
- ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0);
+ ret = af9013_wr_reg_bits(state, 0xd700, 2, 1, 0);
if (ret)
- goto error;
+ goto err;
/* set read-update bit for constellation */
- ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1);
+ ret = af9013_wr_reg_bits(state, 0xd371, 1, 1, 1);
if (ret)
- goto error;
+ goto err;
- /* enable FEC monitor */
- ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1);
+ /* settings for mp2if */
+ if (state->config.ts_mode == AF9013_TS_USB) {
+ /* AF9015 split PSB to 1.5k + 0.5k */
+ ret = af9013_wr_reg_bits(state, 0xd50b, 2, 1, 1);
+ if (ret)
+ goto err;
+ } else {
+ /* AF9013 change the output bit to data7 */
+ ret = af9013_wr_reg_bits(state, 0xd500, 3, 1, 1);
+ if (ret)
+ goto err;
+
+ /* AF9013 set mpeg to full speed */
+ ret = af9013_wr_reg_bits(state, 0xd502, 4, 1, 1);
+ if (ret)
+ goto err;
+ }
+
+ ret = af9013_wr_reg_bits(state, 0xd520, 4, 1, 1);
if (ret)
- goto error;
+ goto err;
/* load OFSM settings */
- deb_info("%s: load ofsm settings\n", __func__);
+ dbg("%s: load ofsm settings", __func__);
len = ARRAY_SIZE(ofsm_init);
init = ofsm_init;
for (i = 0; i < len; i++) {
- ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos,
+ ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos,
init[i].len, init[i].val);
if (ret)
- goto error;
+ goto err;
}
/* load tuner specific settings */
- deb_info("%s: load tuner specific settings\n", __func__);
+ dbg("%s: load tuner specific settings", __func__);
switch (state->config.tuner) {
case AF9013_TUNER_MXL5003D:
len = ARRAY_SIZE(tuner_init_mxl5003d);
@@ -1260,65 +1197,133 @@ static int af9013_init(struct dvb_frontend *fe)
}
for (i = 0; i < len; i++) {
- ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos,
+ ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos,
init[i].len, init[i].val);
if (ret)
- goto error;
+ goto err;
}
- /* set TS mode */
- deb_info("%s: setting ts mode\n", __func__);
- tmp0 = 0; /* parallel mode */
- tmp1 = 0; /* serial mode */
- switch (state->config.output_mode) {
- case AF9013_OUTPUT_MODE_PARALLEL:
- tmp0 = 1;
- break;
- case AF9013_OUTPUT_MODE_SERIAL:
- tmp1 = 1;
- break;
- case AF9013_OUTPUT_MODE_USB:
- /* usb mode for AF9015 */
- default:
- break;
- }
- ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */
+ /* TS mode */
+ ret = af9013_wr_reg_bits(state, 0xd500, 1, 2, state->config.ts_mode);
if (ret)
- goto error;
- ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */
- if (ret)
- goto error;
+ goto err;
/* enable lock led */
- ret = af9013_lock_led(state, 1);
+ ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 1);
if (ret)
- goto error;
+ goto err;
- /* read values needed for signal strength calculation */
- ret = af9013_read_reg_bits(state, 0x9bee, 0, 1,
- &state->signal_strength_en);
- if (ret)
- goto error;
+ /* check if we support signal strength */
+ if (!state->signal_strength_en) {
+ ret = af9013_rd_reg_bits(state, 0x9bee, 0, 1,
+ &state->signal_strength_en);
+ if (ret)
+ goto err;
+ }
- if (state->signal_strength_en) {
- ret = af9013_read_reg(state, 0x9bbd, &state->rf_50);
+ /* read values needed for signal strength calculation */
+ if (state->signal_strength_en && !state->rf_50) {
+ ret = af9013_rd_reg(state, 0x9bbd, &state->rf_50);
if (ret)
- goto error;
- ret = af9013_read_reg(state, 0x9bd0, &state->rf_80);
+ goto err;
+
+ ret = af9013_rd_reg(state, 0x9bd0, &state->rf_80);
if (ret)
- goto error;
- ret = af9013_read_reg(state, 0x9be2, &state->if_50);
+ goto err;
+
+ ret = af9013_rd_reg(state, 0x9be2, &state->if_50);
if (ret)
- goto error;
- ret = af9013_read_reg(state, 0x9be4, &state->if_80);
+ goto err;
+
+ ret = af9013_rd_reg(state, 0x9be4, &state->if_80);
if (ret)
- goto error;
+ goto err;
}
-error:
+ /* SNR */
+ ret = af9013_wr_reg(state, 0xd2e2, 1);
+ if (ret)
+ goto err;
+
+ /* BER / UCB */
+ buf[0] = (10000 >> 0) & 0xff;
+ buf[1] = (10000 >> 8) & 0xff;
+ ret = af9013_wr_regs(state, 0xd385, buf, 2);
+ if (ret)
+ goto err;
+
+ /* enable FEC monitor */
+ ret = af9013_wr_reg_bits(state, 0xd392, 1, 1, 1);
+ if (ret)
+ goto err;
+
+ state->first_tune = true;
+ schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(400));
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
return ret;
}
+static int af9013_sleep(struct dvb_frontend *fe)
+{
+ struct af9013_state *state = fe->demodulator_priv;
+ int ret;
+
+ dbg("%s", __func__);
+
+ /* stop statistics polling */
+ cancel_delayed_work_sync(&state->statistics_work);
+
+ /* disable lock led */
+ ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 0);
+ if (ret)
+ goto err;
+
+ /* power off */
+ ret = af9013_power_ctrl(state, 0);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ int ret;
+ struct af9013_state *state = fe->demodulator_priv;
+
+ dbg("%s: enable=%d", __func__, enable);
+
+ /* gate already open or close */
+ if (state->i2c_gate_state == enable)
+ return 0;
+
+ if (state->config.ts_mode == AF9013_TS_USB)
+ ret = af9013_wr_reg_bits(state, 0xd417, 3, 1, enable);
+ else
+ ret = af9013_wr_reg_bits(state, 0xd607, 2, 1, enable);
+ if (ret)
+ goto err;
+
+ state->i2c_gate_state = enable;
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static void af9013_release(struct dvb_frontend *fe)
+{
+ struct af9013_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
static struct dvb_frontend_ops af9013_ops;
static int af9013_download_firmware(struct af9013_state *state)
@@ -1332,11 +1337,11 @@ static int af9013_download_firmware(struct af9013_state *state)
msleep(100);
/* check whether firmware is already running */
- ret = af9013_read_reg(state, 0x98be, &val);
+ ret = af9013_rd_reg(state, 0x98be, &val);
if (ret)
- goto error;
+ goto err;
else
- deb_info("%s: firmware status:%02x\n", __func__, val);
+ dbg("%s: firmware status=%02x", __func__, val);
if (val == 0x0c) /* fw is running, no need for download */
goto exit;
@@ -1351,7 +1356,7 @@ static int af9013_download_firmware(struct af9013_state *state)
"Please see linux/Documentation/dvb/ for more details" \
" on firmware-problems. (%d)",
fw_file, ret);
- goto error;
+ goto err;
}
info("downloading firmware from file '%s'", fw_file);
@@ -1369,7 +1374,7 @@ static int af9013_download_firmware(struct af9013_state *state)
ret = af9013_write_ofsm_regs(state, 0x50fc,
fw_params, sizeof(fw_params));
if (ret)
- goto error_release;
+ goto err_release;
#define FW_ADDR 0x5100 /* firmware start address */
#define LEN_MAX 16 /* max packet size */
@@ -1383,24 +1388,24 @@ static int af9013_download_firmware(struct af9013_state *state)
(u8 *) &fw->data[fw->size - remaining], len);
if (ret) {
err("firmware download failed:%d", ret);
- goto error_release;
+ goto err_release;
}
}
/* request boot firmware */
- ret = af9013_write_reg(state, 0xe205, 1);
+ ret = af9013_wr_reg(state, 0xe205, 1);
if (ret)
- goto error_release;
+ goto err_release;
for (i = 0; i < 15; i++) {
msleep(100);
/* check firmware status */
- ret = af9013_read_reg(state, 0x98be, &val);
+ ret = af9013_rd_reg(state, 0x98be, &val);
if (ret)
- goto error_release;
+ goto err_release;
- deb_info("%s: firmware status:%02x\n", __func__, val);
+ dbg("%s: firmware status=%02x", __func__, val);
if (val == 0x0c || val == 0x04) /* success or fail */
break;
@@ -1408,43 +1413,21 @@ static int af9013_download_firmware(struct af9013_state *state)
if (val == 0x04) {
err("firmware did not run");
- ret = -1;
+ ret = -ENODEV;
} else if (val != 0x0c) {
err("firmware boot timeout");
- ret = -1;
+ ret = -ENODEV;
}
-error_release:
+err_release:
release_firmware(fw);
-error:
+err:
exit:
if (!ret)
info("found a '%s' in warm state.", af9013_ops.info.name);
return ret;
}
-static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
- int ret;
- struct af9013_state *state = fe->demodulator_priv;
- deb_info("%s: enable:%d\n", __func__, enable);
-
- if (state->config.output_mode == AF9013_OUTPUT_MODE_USB)
- ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable);
- else
- ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable);
-
- return ret;
-}
-
-static void af9013_release(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- kfree(state);
-}
-
-static struct dvb_frontend_ops af9013_ops;
-
struct dvb_frontend *af9013_attach(const struct af9013_config *config,
struct i2c_adapter *i2c)
{
@@ -1455,91 +1438,65 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config,
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL);
if (state == NULL)
- goto error;
+ goto err;
/* setup the state */
state->i2c = i2c;
memcpy(&state->config, config, sizeof(struct af9013_config));
/* download firmware */
- if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) {
+ if (state->config.ts_mode != AF9013_TS_USB) {
ret = af9013_download_firmware(state);
if (ret)
- goto error;
+ goto err;
}
/* firmware version */
- for (i = 0; i < 4; i++) {
- ret = af9013_read_reg(state, 0x5103 + i, &buf[i]);
- if (ret)
- goto error;
- }
- info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
-
- /* chip version */
- ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]);
+ ret = af9013_rd_regs(state, 0x5103, buf, 4);
if (ret)
- goto error;
+ goto err;
- /* ROM version */
- for (i = 0; i < 2; i++) {
- ret = af9013_read_reg(state, 0x116b + i, &buf[i]);
- if (ret)
- goto error;
- }
- deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__,
- buf[2], buf[0], buf[1]);
-
- /* settings for mp2if */
- if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) {
- /* AF9015 split PSB to 1.5k + 0.5k */
- ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1);
- } else {
- /* AF9013 change the output bit to data7 */
- ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1);
- if (ret)
- goto error;
- /* AF9013 set mpeg to full speed */
- ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1);
- }
- if (ret)
- goto error;
- ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1);
- if (ret)
- goto error;
+ info("firmware version %d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
/* set GPIOs */
for (i = 0; i < sizeof(state->config.gpio); i++) {
ret = af9013_set_gpio(state, i, state->config.gpio[i]);
if (ret)
- goto error;
+ goto err;
}
/* create dvb_frontend */
- memcpy(&state->frontend.ops, &af9013_ops,
+ memcpy(&state->fe.ops, &af9013_ops,
sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
+ state->fe.demodulator_priv = state;
+
+ INIT_DELAYED_WORK(&state->statistics_work, af9013_statistics_work);
- return &state->frontend;
-error:
+ return &state->fe;
+err:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(af9013_attach);
static struct dvb_frontend_ops af9013_ops = {
+ .delsys = { SYS_DVBT },
.info = {
- .name = "Afatech AF9013 DVB-T",
- .type = FE_OFDM,
+ .name = "Afatech AF9013",
.frequency_min = 174000000,
.frequency_max = 862000000,
.frequency_stepsize = 250000,
.frequency_tolerance = 0,
- .caps =
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 |
- FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ .caps = FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO |
@@ -1548,24 +1505,22 @@ static struct dvb_frontend_ops af9013_ops = {
},
.release = af9013_release,
+
.init = af9013_init,
.sleep = af9013_sleep,
- .i2c_gate_ctrl = af9013_i2c_gate_ctrl,
+ .get_tune_settings = af9013_get_tune_settings,
.set_frontend = af9013_set_frontend,
.get_frontend = af9013_get_frontend,
- .get_tune_settings = af9013_get_tune_settings,
-
.read_status = af9013_read_status,
- .read_ber = af9013_read_ber,
- .read_signal_strength = af9013_read_signal_strength,
.read_snr = af9013_read_snr,
+ .read_signal_strength = af9013_read_signal_strength,
+ .read_ber = af9013_read_ber,
.read_ucblocks = af9013_read_ucblocks,
-};
-module_param_named(debug, af9013_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+ .i2c_gate_ctrl = af9013_i2c_gate_ctrl,
+};
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver");
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h
index e53d873f7555..b973fc5a0384 100644
--- a/drivers/media/dvb/frontends/af9013.h
+++ b/drivers/media/dvb/frontends/af9013.h
@@ -2,6 +2,7 @@
* Afatech AF9013 demodulator driver
*
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
*
* Thanks to Afatech who kindly provided information.
*
@@ -21,33 +22,11 @@
*
*/
-#ifndef _AF9013_H_
-#define _AF9013_H_
+#ifndef AF9013_H
+#define AF9013_H
#include <linux/dvb/frontend.h>
-enum af9013_ts_mode {
- AF9013_OUTPUT_MODE_PARALLEL,
- AF9013_OUTPUT_MODE_SERIAL,
- AF9013_OUTPUT_MODE_USB, /* only for AF9015 */
-};
-
-enum af9013_tuner {
- AF9013_TUNER_MXL5003D = 3, /* MaxLinear */
- AF9013_TUNER_MXL5005D = 13, /* MaxLinear */
- AF9013_TUNER_MXL5005R = 30, /* MaxLinear */
- AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */
- AF9013_TUNER_MT2060 = 130, /* Microtune */
- AF9013_TUNER_MC44S803 = 133, /* Freescale */
- AF9013_TUNER_QT1010 = 134, /* Quantek */
- AF9013_TUNER_UNKNOWN = 140, /* for can tuners ? */
- AF9013_TUNER_MT2060_2 = 147, /* Microtune */
- AF9013_TUNER_TDA18271 = 156, /* NXP */
- AF9013_TUNER_QT1010A = 162, /* Quantek */
- AF9013_TUNER_MXL5007T = 177, /* MaxLinear */
- AF9013_TUNER_TDA18218 = 179, /* NXP */
-};
-
/* AF9013/5 GPIOs (mostly guessed)
demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
demod#1-gpio#1 - xtal setting (?)
@@ -55,44 +34,74 @@ enum af9013_tuner {
demod#2-gpio#0 - tuner#2
demod#2-gpio#1 - xtal setting (?)
*/
+
+struct af9013_config {
+ /*
+ * I2C address
+ */
+ u8 i2c_addr;
+
+ /*
+ * clock
+ * 20480000, 25000000, 28000000, 28800000
+ */
+ u32 clock;
+
+ /*
+ * tuner
+ */
+#define AF9013_TUNER_MXL5003D 3 /* MaxLinear */
+#define AF9013_TUNER_MXL5005D 13 /* MaxLinear */
+#define AF9013_TUNER_MXL5005R 30 /* MaxLinear */
+#define AF9013_TUNER_ENV77H11D5 129 /* Panasonic */
+#define AF9013_TUNER_MT2060 130 /* Microtune */
+#define AF9013_TUNER_MC44S803 133 /* Freescale */
+#define AF9013_TUNER_QT1010 134 /* Quantek */
+#define AF9013_TUNER_UNKNOWN 140 /* for can tuners ? */
+#define AF9013_TUNER_MT2060_2 147 /* Microtune */
+#define AF9013_TUNER_TDA18271 156 /* NXP */
+#define AF9013_TUNER_QT1010A 162 /* Quantek */
+#define AF9013_TUNER_MXL5007T 177 /* MaxLinear */
+#define AF9013_TUNER_TDA18218 179 /* NXP */
+ u8 tuner;
+
+ /*
+ * IF frequency
+ */
+ u32 if_frequency;
+
+ /*
+ * TS settings
+ */
+#define AF9013_TS_USB 0
+#define AF9013_TS_PARALLEL 1
+#define AF9013_TS_SERIAL 2
+ u8 ts_mode:2;
+
+ /*
+ * input spectrum inversion
+ */
+ bool spec_inv;
+
+ /*
+ * firmware API version
+ */
+ u8 api_version[4];
+
+ /*
+ * GPIOs
+ */
#define AF9013_GPIO_ON (1 << 0)
#define AF9013_GPIO_EN (1 << 1)
#define AF9013_GPIO_O (1 << 2)
#define AF9013_GPIO_I (1 << 3)
-
#define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN)
#define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
-
#define AF9013_GPIO_TUNER_ON (AF9013_GPIO_ON|AF9013_GPIO_EN)
#define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
-
-struct af9013_config {
- /* demodulator's I2C address */
- u8 demod_address;
-
- /* frequencies in kHz */
- u32 adc_clock;
-
- /* tuner ID */
- u8 tuner;
-
- /* tuner IF */
- u16 tuner_if;
-
- /* TS data output mode */
- u8 output_mode:2;
-
- /* RF spectrum inversion */
- u8 rf_spec_inv:1;
-
- /* API version */
- u8 api_version[4];
-
- /* GPIOs */
u8 gpio[4];
};
-
#if defined(CONFIG_DVB_AF9013) || \
(defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE))
extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
@@ -106,4 +115,4 @@ const struct af9013_config *config, struct i2c_adapter *i2c)
}
#endif /* CONFIG_DVB_AF9013 */
-#endif /* _AF9013_H_ */
+#endif /* AF9013_H */
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h
index e00b2a4a2db6..fa848af6e9b4 100644
--- a/drivers/media/dvb/frontends/af9013_priv.h
+++ b/drivers/media/dvb/frontends/af9013_priv.h
@@ -2,6 +2,7 @@
* Afatech AF9013 demodulator driver
*
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
*
* Thanks to Afatech who kindly provided information.
*
@@ -21,24 +22,19 @@
*
*/
-#ifndef _AF9013_PRIV_
-#define _AF9013_PRIV_
+#ifndef AF9013_PRIV_H
+#define AF9013_PRIV_H
-#define LOG_PREFIX "af9013"
-extern int af9013_debug;
-
-#define dprintk(var, level, args...) \
- do { if ((var & level)) printk(args); } while (0)
+#include "dvb_frontend.h"
+#include "af9013.h"
+#include <linux/firmware.h>
-#define debug_dump(b, l, func) {\
- int loop_; \
- for (loop_ = 0; loop_ < l; loop_++) \
- func("%02x ", b[loop_]); \
- func("\n");\
-}
-
-#define deb_info(args...) dprintk(af9013_debug, 0x01, args)
+#define LOG_PREFIX "af9013"
+#undef dbg
+#define dbg(f, arg...) \
+ if (af9013_debug) \
+ printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
#undef err
#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
#undef info
@@ -48,70 +44,71 @@ extern int af9013_debug;
#define AF9013_DEFAULT_FIRMWARE "dvb-fe-af9013.fw"
-struct regdesc {
+struct af9013_reg_bit {
u16 addr;
u8 pos:4;
u8 len:4;
u8 val;
};
-struct snr_table {
+struct af9013_snr {
u32 val;
u8 snr;
};
-struct coeff {
- u32 adc_clock;
- fe_bandwidth_t bw;
+struct af9013_coeff {
+ u32 clock;
+ u32 bandwidth_hz;
u8 val[24];
};
/* pre-calculated coeff lookup table */
-static struct coeff coeff_table[] = {
+static const struct af9013_coeff coeff_lut[] = {
/* 28.800 MHz */
- { 28800, BANDWIDTH_8_MHZ, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
+ { 28800000, 8000000, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a,
0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } },
- { 28800, BANDWIDTH_7_MHZ, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
+ { 28800000, 7000000, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38,
0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } },
- { 28800, BANDWIDTH_6_MHZ, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
+ { 28800000, 6000000, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7,
0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } },
/* 20.480 MHz */
- { 20480, BANDWIDTH_8_MHZ, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
+ { 20480000, 8000000, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92,
0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } },
- { 20480, BANDWIDTH_7_MHZ, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
+ { 20480000, 7000000, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00,
0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } },
- { 20480, BANDWIDTH_6_MHZ, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
+ { 20480000, 6000000, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d,
0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } },
/* 28.000 MHz */
- { 28000, BANDWIDTH_8_MHZ, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
+ { 28000000, 8000000, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f,
0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } },
- { 28000, BANDWIDTH_7_MHZ, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
+ { 28000000, 7000000, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49,
0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } },
- { 28000, BANDWIDTH_6_MHZ, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
+ { 28000000, 6000000, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63,
0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } },
/* 25.000 MHz */
- { 25000, BANDWIDTH_8_MHZ, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
+ { 25000000, 8000000, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e,
0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } },
- { 25000, BANDWIDTH_7_MHZ, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
+ { 25000000, 7000000, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7,
0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } },
- { 25000, BANDWIDTH_6_MHZ, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
+ { 25000000, 6000000, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f,
0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } },
};
/* QPSK SNR lookup table */
-static struct snr_table qpsk_snr_table[] = {
+static const struct af9013_snr qpsk_snr_lut[] = {
+ { 0x000000, 0 },
{ 0x0b4771, 0 },
{ 0x0c1aed, 1 },
{ 0x0d0d27, 2 },
@@ -131,7 +128,8 @@ static struct snr_table qpsk_snr_table[] = {
};
/* QAM16 SNR lookup table */
-static struct snr_table qam16_snr_table[] = {
+static const struct af9013_snr qam16_snr_lut[] = {
+ { 0x000000, 0 },
{ 0x05eb62, 5 },
{ 0x05fecf, 6 },
{ 0x060b80, 7 },
@@ -151,7 +149,8 @@ static struct snr_table qam16_snr_table[] = {
};
/* QAM64 SNR lookup table */
-static struct snr_table qam64_snr_table[] = {
+static const struct af9013_snr qam64_snr_lut[] = {
+ { 0x000000, 0 },
{ 0x03109b, 12 },
{ 0x0310d4, 13 },
{ 0x031920, 14 },
@@ -170,7 +169,7 @@ static struct snr_table qam64_snr_table[] = {
{ 0xffffff, 27 },
};
-static struct regdesc ofsm_init[] = {
+static const struct af9013_reg_bit ofsm_init[] = {
{ 0xd73a, 0, 8, 0xa1 },
{ 0xd73b, 0, 8, 0x1f },
{ 0xd73c, 4, 4, 0x0a },
@@ -252,7 +251,7 @@ static struct regdesc ofsm_init[] = {
/* Panasonic ENV77H11D5 tuner init
AF9013_TUNER_ENV77H11D5 = 129 */
-static struct regdesc tuner_init_env77h11d5[] = {
+static const struct af9013_reg_bit tuner_init_env77h11d5[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x03 },
{ 0x9bbe, 0, 8, 0x01 },
@@ -318,7 +317,7 @@ static struct regdesc tuner_init_env77h11d5[] = {
/* Microtune MT2060 tuner init
AF9013_TUNER_MT2060 = 130 */
-static struct regdesc tuner_init_mt2060[] = {
+static const struct af9013_reg_bit tuner_init_mt2060[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x07 },
{ 0xd1a0, 1, 1, 0x01 },
@@ -395,7 +394,7 @@ static struct regdesc tuner_init_mt2060[] = {
/* Microtune MT2060 tuner init
AF9013_TUNER_MT2060_2 = 147 */
-static struct regdesc tuner_init_mt2060_2[] = {
+static const struct af9013_reg_bit tuner_init_mt2060_2[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x06 },
{ 0x9bbe, 0, 8, 0x01 },
@@ -462,7 +461,7 @@ static struct regdesc tuner_init_mt2060_2[] = {
/* MaxLinear MXL5003 tuner init
AF9013_TUNER_MXL5003D = 3 */
-static struct regdesc tuner_init_mxl5003d[] = {
+static const struct af9013_reg_bit tuner_init_mxl5003d[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x09 },
{ 0xd1a0, 1, 1, 0x01 },
@@ -534,7 +533,7 @@ static struct regdesc tuner_init_mxl5003d[] = {
AF9013_TUNER_MXL5005D = 13
AF9013_TUNER_MXL5005R = 30
AF9013_TUNER_MXL5007T = 177 */
-static struct regdesc tuner_init_mxl5005[] = {
+static const struct af9013_reg_bit tuner_init_mxl5005[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x07 },
{ 0xd1a0, 1, 1, 0x01 },
@@ -613,7 +612,7 @@ static struct regdesc tuner_init_mxl5005[] = {
/* Quantek QT1010 tuner init
AF9013_TUNER_QT1010 = 134
AF9013_TUNER_QT1010A = 162 */
-static struct regdesc tuner_init_qt1010[] = {
+static const struct af9013_reg_bit tuner_init_qt1010[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x09 },
{ 0xd1a0, 1, 1, 0x01 },
@@ -690,7 +689,7 @@ static struct regdesc tuner_init_qt1010[] = {
/* Freescale MC44S803 tuner init
AF9013_TUNER_MC44S803 = 133 */
-static struct regdesc tuner_init_mc44s803[] = {
+static const struct af9013_reg_bit tuner_init_mc44s803[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x06 },
{ 0xd1a0, 1, 1, 0x01 },
@@ -772,7 +771,7 @@ static struct regdesc tuner_init_mc44s803[] = {
/* unknown, probably for tin can tuner, tuner init
AF9013_TUNER_UNKNOWN = 140 */
-static struct regdesc tuner_init_unknown[] = {
+static const struct af9013_reg_bit tuner_init_unknown[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x02 },
{ 0xd1a0, 1, 1, 0x01 },
@@ -845,7 +844,7 @@ static struct regdesc tuner_init_unknown[] = {
/* NXP TDA18271 & TDA18218 tuner init
AF9013_TUNER_TDA18271 = 156
AF9013_TUNER_TDA18218 = 179 */
-static struct regdesc tuner_init_tda18271[] = {
+static const struct af9013_reg_bit tuner_init_tda18271[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x04 },
{ 0xd1a0, 1, 1, 0x01 },
@@ -920,4 +919,4 @@ static struct regdesc tuner_init_tda18271[] = {
{ 0x9bee, 0, 1, 0x01 },
};
-#endif /* _AF9013_PRIV_ */
+#endif /* AF9013_PRIV_H */
diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c
index 1539ea1f81ac..a2261ea2cf82 100644
--- a/drivers/media/dvb/frontends/atbm8830.c
+++ b/drivers/media/dvb/frontends/atbm8830.c
@@ -267,8 +267,7 @@ static void atbm8830_release(struct dvb_frontend *fe)
kfree(state);
}
-static int atbm8830_set_fe(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fe_params)
+static int atbm8830_set_fe(struct dvb_frontend *fe)
{
struct atbm_state *priv = fe->demodulator_priv;
int i;
@@ -279,7 +278,7 @@ static int atbm8830_set_fe(struct dvb_frontend *fe,
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- fe->ops.tuner_ops.set_params(fe, fe_params);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -298,31 +297,31 @@ static int atbm8830_set_fe(struct dvb_frontend *fe,
return 0;
}
-static int atbm8830_get_fe(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fe_params)
+static int atbm8830_get_fe(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
dprintk("%s\n", __func__);
/* TODO: get real readings from device */
/* inversion status */
- fe_params->inversion = INVERSION_OFF;
+ c->inversion = INVERSION_OFF;
/* bandwidth */
- fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ c->bandwidth_hz = 8000000;
- fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
- fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
+ c->code_rate_HP = FEC_AUTO;
+ c->code_rate_LP = FEC_AUTO;
- fe_params->u.ofdm.constellation = QAM_AUTO;
+ c->modulation = QAM_AUTO;
/* transmission mode */
- fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+ c->transmission_mode = TRANSMISSION_MODE_AUTO;
/* guard interval */
- fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+ c->guard_interval = GUARD_INTERVAL_AUTO;
/* hierarchy */
- fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ c->hierarchy = HIERARCHY_NONE;
return 0;
}
@@ -429,9 +428,9 @@ static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
}
static struct dvb_frontend_ops atbm8830_ops = {
+ .delsys = { SYS_DMBTH },
.info = {
.name = "AltoBeam ATBM8830/8831 DMB-TH",
- .type = FE_OFDM,
.frequency_min = 474000000,
.frequency_max = 858000000,
.frequency_stepsize = 10000,
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
index 2b248c12f404..55b6390198e3 100644
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ b/drivers/media/dvb/frontends/au8522_decoder.c
@@ -839,15 +839,4 @@ static struct i2c_driver au8522_driver = {
.id_table = au8522_id,
};
-static __init int init_au8522(void)
-{
- return i2c_add_driver(&au8522_driver);
-}
-
-static __exit void exit_au8522(void)
-{
- i2c_del_driver(&au8522_driver);
-}
-
-module_init(init_au8522);
-module_exit(exit_au8522);
+module_i2c_driver(au8522_driver);
diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c
index 1d572940e243..25f650934c73 100644
--- a/drivers/media/dvb/frontends/au8522_dig.c
+++ b/drivers/media/dvb/frontends/au8522_dig.c
@@ -576,27 +576,22 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int au8522_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int au8522_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct au8522_state *state = fe->demodulator_priv;
int ret = -EINVAL;
- dprintk("%s(frequency=%d)\n", __func__, p->frequency);
+ dprintk("%s(frequency=%d)\n", __func__, c->frequency);
- if ((state->current_frequency == p->frequency) &&
- (state->current_modulation == p->u.vsb.modulation))
+ if ((state->current_frequency == c->frequency) &&
+ (state->current_modulation == c->modulation))
return 0;
- au8522_enable_modulation(fe, p->u.vsb.modulation);
-
- /* Allow the demod to settle */
- msleep(100);
-
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- ret = fe->ops.tuner_ops.set_params(fe, p);
+ ret = fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -604,7 +599,12 @@ static int au8522_set_frontend(struct dvb_frontend *fe,
if (ret < 0)
return ret;
- state->current_frequency = p->frequency;
+ /* Allow the tuner to settle */
+ msleep(100);
+
+ au8522_enable_modulation(fe, c->modulation);
+
+ state->current_frequency = c->frequency;
return 0;
}
@@ -862,7 +862,36 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
static int au8522_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
- return au8522_read_snr(fe, signal_strength);
+ /* borrowed from lgdt330x.c
+ *
+ * Calculate strength from SNR up to 35dB
+ * Even though the SNR can go higher than 35dB,
+ * there is some comfort factor in having a range of
+ * strong signals that can show at 100%
+ */
+ u16 snr;
+ u32 tmp;
+ int ret = au8522_read_snr(fe, &snr);
+
+ *signal_strength = 0;
+
+ if (0 == ret) {
+ /* The following calculation method was chosen
+ * purely for the sake of code re-use from the
+ * other demod drivers that use this method */
+
+ /* Convert from SNR in dB * 10 to 8.24 fixed-point */
+ tmp = (snr * ((1 << 24) / 10));
+
+ /* Convert from 8.24 fixed-point to
+ * scale the range 0 - 35*2^24 into 0 - 65535*/
+ if (tmp >= 8960 * 0x10000)
+ *signal_strength = 0xffff;
+ else
+ *signal_strength = tmp / 8960;
+ }
+
+ return ret;
}
static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
@@ -882,13 +911,13 @@ static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
return au8522_read_ucblocks(fe, ber);
}
-static int au8522_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int au8522_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct au8522_state *state = fe->demodulator_priv;
- p->frequency = state->current_frequency;
- p->u.vsb.modulation = state->current_modulation;
+ c->frequency = state->current_frequency;
+ c->modulation = state->current_modulation;
return 0;
}
@@ -981,10 +1010,9 @@ error:
EXPORT_SYMBOL(au8522_attach);
static struct dvb_frontend_ops au8522_ops = {
-
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name = "Auvitek AU8522 QAM/8VSB Frontend",
- .type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index 8aff5868a5e1..033cd7ad3ca2 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -479,16 +479,16 @@ static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq)
return -EINVAL;
}
-static int bcm3510_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *p)
+static int bcm3510_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct bcm3510_state* st = fe->demodulator_priv;
struct bcm3510_hab_cmd_ext_acquire cmd;
struct bcm3510_hab_cmd_bert_control bert;
int ret;
memset(&cmd,0,sizeof(cmd));
- switch (p->u.vsb.modulation) {
+ switch (c->modulation) {
case QAM_256:
cmd.ACQUIRE0.MODE = 0x1;
cmd.ACQUIRE1.SYM_RATE = 0x1;
@@ -499,7 +499,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe,
cmd.ACQUIRE1.SYM_RATE = 0x2;
cmd.ACQUIRE1.IF_FREQ = 0x1;
break;
-/* case QAM_256:
+#if 0
+ case QAM_256:
cmd.ACQUIRE0.MODE = 0x3;
break;
case QAM_128:
@@ -513,7 +514,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe,
break;
case QAM_16:
cmd.ACQUIRE0.MODE = 0x7;
- break;*/
+ break;
+#endif
case VSB_8:
cmd.ACQUIRE0.MODE = 0x8;
cmd.ACQUIRE1.SYM_RATE = 0x0;
@@ -552,7 +554,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe,
bcm3510_bert_reset(st);
- if ((ret = bcm3510_set_freq(st,p->frequency)) < 0)
+ ret = bcm3510_set_freq(st, c->frequency);
+ if (ret < 0)
return ret;
memset(&st->status1,0,sizeof(st->status1));
@@ -819,10 +822,9 @@ error:
EXPORT_SYMBOL(bcm3510_attach);
static struct dvb_frontend_ops bcm3510_ops = {
-
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name = "Broadcom BCM3510 VSB/QAM frontend",
- .type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 803000000,
/* stepsize is just a guess */
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h
index 5e431ebd089b..53e4d0dbb745 100644
--- a/drivers/media/dvb/frontends/bsbe1.h
+++ b/drivers/media/dvb/frontends/bsbe1.h
@@ -69,18 +69,19 @@ static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra
return 0;
}
-static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int alps_bsbe1_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
int ret;
u8 data[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
struct i2c_adapter *i2c = fe->tuner_priv;
- if ((params->frequency < 950000) || (params->frequency > 2150000))
+ if ((p->frequency < 950000) || (p->frequency > 2150000))
return -EINVAL;
- div = params->frequency / 1000;
+ div = p->frequency / 1000;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = 0x80 | ((div & 0x18000) >> 10) | 0x1;
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
index c480c839b302..c2a578e1314d 100644
--- a/drivers/media/dvb/frontends/bsru6.h
+++ b/drivers/media/dvb/frontends/bsru6.h
@@ -101,23 +101,24 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra
return 0;
}
-static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 buf[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
struct i2c_adapter *i2c = fe->tuner_priv;
- if ((params->frequency < 950000) || (params->frequency > 2150000))
+ if ((p->frequency < 950000) || (p->frequency > 2150000))
return -EINVAL;
- div = (params->frequency + (125 - 1)) / 125; // round correctly
+ div = (p->frequency + (125 - 1)) / 125; /* round correctly */
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
buf[3] = 0xC4;
- if (params->frequency > 1530000)
+ if (p->frequency > 1530000)
buf[3] = 0xc0;
if (fe->ops.i2c_gate_ctrl)
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
index 0142214b0133..f2a90f990ce3 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -121,7 +121,8 @@ static int cx22700_set_inversion (struct cx22700_state* state, int inversion)
}
}
-static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_parameters *p)
+static int cx22700_set_tps(struct cx22700_state *state,
+ struct dtv_frontend_properties *p)
{
static const u8 qam_tab [4] = { 0, 1, 0, 2 };
static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
@@ -146,25 +147,25 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet
p->transmission_mode != TRANSMISSION_MODE_8K)
return -EINVAL;
- if (p->constellation != QPSK &&
- p->constellation != QAM_16 &&
- p->constellation != QAM_64)
+ if (p->modulation != QPSK &&
+ p->modulation != QAM_16 &&
+ p->modulation != QAM_64)
return -EINVAL;
- if (p->hierarchy_information < HIERARCHY_NONE ||
- p->hierarchy_information > HIERARCHY_4)
+ if (p->hierarchy < HIERARCHY_NONE ||
+ p->hierarchy > HIERARCHY_4)
return -EINVAL;
- if (p->bandwidth < BANDWIDTH_8_MHZ || p->bandwidth > BANDWIDTH_6_MHZ)
+ if (p->bandwidth_hz > 8000000 || p->bandwidth_hz < 6000000)
return -EINVAL;
- if (p->bandwidth == BANDWIDTH_7_MHZ)
+ if (p->bandwidth_hz == 7000000)
cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10));
else
cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10));
- val = qam_tab[p->constellation - QPSK];
- val |= p->hierarchy_information - HIERARCHY_NONE;
+ val = qam_tab[p->modulation - QPSK];
+ val |= p->hierarchy - HIERARCHY_NONE;
cx22700_writereg (state, 0x04, val);
@@ -184,7 +185,8 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet
return 0;
}
-static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_parameters *p)
+static int cx22700_get_tps(struct cx22700_state *state,
+ struct dtv_frontend_properties *p)
{
static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
@@ -199,14 +201,14 @@ static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_paramet
val = cx22700_readreg (state, 0x01);
if ((val & 0x7) > 4)
- p->hierarchy_information = HIERARCHY_AUTO;
+ p->hierarchy = HIERARCHY_AUTO;
else
- p->hierarchy_information = HIERARCHY_NONE + (val & 0x7);
+ p->hierarchy = HIERARCHY_NONE + (val & 0x7);
if (((val >> 3) & 0x3) > 2)
- p->constellation = QAM_AUTO;
+ p->modulation = QAM_AUTO;
else
- p->constellation = qam_tab[(val >> 3) & 0x3];
+ p->modulation = qam_tab[(val >> 3) & 0x3];
val = cx22700_readreg (state, 0x02);
@@ -318,33 +320,35 @@ static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx22700_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx22700_state* state = fe->demodulator_priv;
cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
cx22700_writereg (state, 0x00, 0x00);
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- cx22700_set_inversion (state, p->inversion);
- cx22700_set_tps (state, &p->u.ofdm);
+ cx22700_set_inversion(state, c->inversion);
+ cx22700_set_tps(state, c);
cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */
cx22700_writereg (state, 0x00, 0x01); /* restart acquire */
return 0;
}
-static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx22700_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx22700_state* state = fe->demodulator_priv;
u8 reg09 = cx22700_readreg (state, 0x09);
- p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
- return cx22700_get_tps (state, &p->u.ofdm);
+ c->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
+ return cx22700_get_tps(state, c);
}
static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
@@ -401,10 +405,9 @@ error:
}
static struct dvb_frontend_ops cx22700_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "Conexant CX22700 DVB-T",
- .type = FE_OFDM,
.frequency_min = 470000000,
.frequency_max = 860000000,
.frequency_stepsize = 166667,
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 3139558148ba..edc8eafc5c09 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -146,7 +146,7 @@ static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
/* Retrieve the demod settings */
static int cx22702_get_tps(struct cx22702_state *state,
- struct dvb_ofdm_parameters *p)
+ struct dtv_frontend_properties *p)
{
u8 val;
@@ -157,27 +157,27 @@ static int cx22702_get_tps(struct cx22702_state *state,
val = cx22702_readreg(state, 0x01);
switch ((val & 0x18) >> 3) {
case 0:
- p->constellation = QPSK;
+ p->modulation = QPSK;
break;
case 1:
- p->constellation = QAM_16;
+ p->modulation = QAM_16;
break;
case 2:
- p->constellation = QAM_64;
+ p->modulation = QAM_64;
break;
}
switch (val & 0x07) {
case 0:
- p->hierarchy_information = HIERARCHY_NONE;
+ p->hierarchy = HIERARCHY_NONE;
break;
case 1:
- p->hierarchy_information = HIERARCHY_1;
+ p->hierarchy = HIERARCHY_1;
break;
case 2:
- p->hierarchy_information = HIERARCHY_2;
+ p->hierarchy = HIERARCHY_2;
break;
case 3:
- p->hierarchy_information = HIERARCHY_4;
+ p->hierarchy = HIERARCHY_4;
break;
}
@@ -260,14 +260,14 @@ static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int cx22702_set_tps(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int cx22702_set_tps(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u8 val;
struct cx22702_state *state = fe->demodulator_priv;
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -277,14 +277,14 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
/* set bandwidth */
val = cx22702_readreg(state, 0x0C) & 0xcf;
- switch (p->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (p->bandwidth_hz) {
+ case 6000000:
val |= 0x20;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
val |= 0x10;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
break;
default:
dprintk("%s: invalid bandwidth\n", __func__);
@@ -292,15 +292,15 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
cx22702_writereg(state, 0x0C, val);
- p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
+ p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
/* use auto configuration? */
- if ((p->u.ofdm.hierarchy_information == HIERARCHY_AUTO) ||
- (p->u.ofdm.constellation == QAM_AUTO) ||
- (p->u.ofdm.code_rate_HP == FEC_AUTO) ||
- (p->u.ofdm.code_rate_LP == FEC_AUTO) ||
- (p->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO) ||
- (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO)) {
+ if ((p->hierarchy == HIERARCHY_AUTO) ||
+ (p->modulation == QAM_AUTO) ||
+ (p->code_rate_HP == FEC_AUTO) ||
+ (p->code_rate_LP == FEC_AUTO) ||
+ (p->guard_interval == GUARD_INTERVAL_AUTO) ||
+ (p->transmission_mode == TRANSMISSION_MODE_AUTO)) {
/* TPS Source - use hardware driven values */
cx22702_writereg(state, 0x06, 0x10);
@@ -316,7 +316,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
/* manually programmed values */
- switch (p->u.ofdm.constellation) { /* mask 0x18 */
+ switch (p->modulation) { /* mask 0x18 */
case QPSK:
val = 0x00;
break;
@@ -327,10 +327,10 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
val = 0x10;
break;
default:
- dprintk("%s: invalid constellation\n", __func__);
+ dprintk("%s: invalid modulation\n", __func__);
return -EINVAL;
}
- switch (p->u.ofdm.hierarchy_information) { /* mask 0x07 */
+ switch (p->hierarchy) { /* mask 0x07 */
case HIERARCHY_NONE:
break;
case HIERARCHY_1:
@@ -348,7 +348,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
cx22702_writereg(state, 0x06, val);
- switch (p->u.ofdm.code_rate_HP) { /* mask 0x38 */
+ switch (p->code_rate_HP) { /* mask 0x38 */
case FEC_NONE:
case FEC_1_2:
val = 0x00;
@@ -369,7 +369,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
dprintk("%s: invalid code_rate_HP\n", __func__);
return -EINVAL;
}
- switch (p->u.ofdm.code_rate_LP) { /* mask 0x07 */
+ switch (p->code_rate_LP) { /* mask 0x07 */
case FEC_NONE:
case FEC_1_2:
break;
@@ -391,7 +391,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
cx22702_writereg(state, 0x07, val);
- switch (p->u.ofdm.guard_interval) { /* mask 0x0c */
+ switch (p->guard_interval) { /* mask 0x0c */
case GUARD_INTERVAL_1_32:
val = 0x00;
break;
@@ -408,7 +408,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
dprintk("%s: invalid guard_interval\n", __func__);
return -EINVAL;
}
- switch (p->u.ofdm.transmission_mode) { /* mask 0x03 */
+ switch (p->transmission_mode) { /* mask 0x03 */
case TRANSMISSION_MODE_2K:
break;
case TRANSMISSION_MODE_8K:
@@ -502,10 +502,26 @@ static int cx22702_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
struct cx22702_state *state = fe->demodulator_priv;
+ u8 reg23;
- u16 rs_ber;
- rs_ber = cx22702_readreg(state, 0x23);
- *signal_strength = (rs_ber << 8) | rs_ber;
+ /*
+ * Experience suggests that the strength signal register works as
+ * follows:
+ * - In the absence of signal, value is 0xff.
+ * - In the presence of a weak signal, bit 7 is set, not sure what
+ * the lower 7 bits mean.
+ * - In the presence of a strong signal, the register holds a 7-bit
+ * value (bit 7 is cleared), with greater values standing for
+ * weaker signals.
+ */
+ reg23 = cx22702_readreg(state, 0x23);
+ if (reg23 & 0x80) {
+ *signal_strength = 0;
+ } else {
+ reg23 = ~reg23 & 0x7f;
+ /* Scale to 16 bit */
+ *signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5);
+ }
return 0;
}
@@ -546,15 +562,15 @@ static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
return 0;
}
-static int cx22702_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int cx22702_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx22702_state *state = fe->demodulator_priv;
u8 reg0C = cx22702_readreg(state, 0x0C);
- p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
- return cx22702_get_tps(state, &p->u.ofdm);
+ c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
+ return cx22702_get_tps(state, c);
}
static int cx22702_get_tune_settings(struct dvb_frontend *fe,
@@ -603,10 +619,9 @@ error:
EXPORT_SYMBOL(cx22702_attach);
static const struct dvb_frontend_ops cx22702_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "Conexant CX22702 DVB-T",
- .type = FE_OFDM,
.frequency_min = 177000000,
.frequency_max = 858000000,
.frequency_stepsize = 166666,
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index bf9c999aa470..5101f10f2d7a 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -531,26 +531,27 @@ static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24110_set_frontend(struct dvb_frontend *fe)
{
struct cx24110_state *state = fe->demodulator_priv;
-
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- cx24110_set_inversion (state, p->inversion);
- cx24110_set_fec (state, p->u.qpsk.fec_inner);
- cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
+ cx24110_set_inversion(state, p->inversion);
+ cx24110_set_fec(state, p->fec_inner);
+ cx24110_set_symbolrate(state, p->symbol_rate);
cx24110_writereg(state,0x04,0x05); /* start acquisition */
return 0;
}
-static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24110_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct cx24110_state *state = fe->demodulator_priv;
s32 afc; unsigned sclk;
@@ -571,7 +572,7 @@ static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
p->frequency += afc;
p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?
INVERSION_ON : INVERSION_OFF;
- p->u.qpsk.fec_inner = cx24110_get_fec (state);
+ p->fec_inner = cx24110_get_fec(state);
return 0;
}
@@ -623,10 +624,9 @@ error:
}
static struct dvb_frontend_ops cx24110_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "Conexant CX24110 DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1011, /* kHz for QPSK frontends */
diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c
index c341d57d5e81..3883c3b31aef 100644
--- a/drivers/media/dvb/frontends/cx24113.c
+++ b/drivers/media/dvb/frontends/cx24113.c
@@ -476,21 +476,21 @@ static int cx24113_init(struct dvb_frontend *fe)
return ret;
}
-static int cx24113_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int cx24113_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx24113_state *state = fe->tuner_priv;
/* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
u32 roll_off = 675;
u32 bw;
- bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000;
+ bw = ((c->symbol_rate/100) * roll_off) / 1000;
bw += (10000000/100) + 5;
bw /= 10;
bw += 1000;
cx24113_set_bandwidth(state, bw);
- cx24113_set_frequency(state, p->frequency);
+ cx24113_set_frequency(state, c->frequency);
msleep(5);
return cx24113_get_status(fe, &bw);
}
@@ -547,11 +547,9 @@ static const struct dvb_tuner_ops cx24113_tuner_ops = {
.release = cx24113_release,
.init = cx24113_init,
- .sleep = NULL,
.set_params = cx24113_set_params,
.get_frequency = cx24113_get_frequency,
- .get_bandwidth = NULL,
.get_status = cx24113_get_status,
};
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c
index ccd05255d527..b48879186537 100644
--- a/drivers/media/dvb/frontends/cx24116.c
+++ b/drivers/media/dvb/frontends/cx24116.c
@@ -1212,25 +1212,10 @@ static int cx24116_sleep(struct dvb_frontend *fe)
return 0;
}
-static int cx24116_set_property(struct dvb_frontend *fe,
- struct dtv_property *tvp)
-{
- dprintk("%s(..)\n", __func__);
- return 0;
-}
-
-static int cx24116_get_property(struct dvb_frontend *fe,
- struct dtv_property *tvp)
-{
- dprintk("%s(..)\n", __func__);
- return 0;
-}
-
/* dvb-core told us to tune, the tv property cache will be complete,
* it's safe for is to pull values and use them for tuning purposes.
*/
-static int cx24116_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int cx24116_set_frontend(struct dvb_frontend *fe)
{
struct cx24116_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -1455,12 +1440,20 @@ tuned: /* Set/Reset B/W */
return cx24116_cmd_execute(fe, &cmd);
}
-static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
+static int cx24116_tune(struct dvb_frontend *fe, bool re_tune,
unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
{
+ /*
+ * It is safe to discard "params" here, as the DVB core will sync
+ * fe->dtv_property_cache with fepriv->parameters_in, where the
+ * DVBv3 params are stored. The only practical usage for it indicate
+ * that re-tuning is needed, e. g. (fepriv->state & FESTATE_RETUNE) is
+ * true.
+ */
+
*delay = HZ / 5;
- if (params) {
- int ret = cx24116_set_frontend(fe, params);
+ if (re_tune) {
+ int ret = cx24116_set_frontend(fe);
if (ret)
return ret;
}
@@ -1473,10 +1466,9 @@ static int cx24116_get_algo(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops cx24116_ops = {
-
+ .delsys = { SYS_DVBS, SYS_DVBS2 },
.info = {
.name = "Conexant CX24116/CX24118",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1011, /* kHz for QPSK frontends */
@@ -1507,8 +1499,6 @@ static struct dvb_frontend_ops cx24116_ops = {
.get_frontend_algo = cx24116_get_algo,
.tune = cx24116_tune,
- .set_property = cx24116_set_property,
- .get_property = cx24116_get_property,
.set_frontend = cx24116_set_frontend,
};
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index b1dd8acc607a..7e28b4ee7d4f 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -526,9 +526,9 @@ static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
* to be configured and the correct band selected.
* Calculate those values.
*/
-static int cx24123_pll_calculate(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int cx24123_pll_calculate(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct cx24123_state *state = fe->demodulator_priv;
u32 ndiv = 0, adiv = 0, vco_div = 0;
int i = 0;
@@ -548,8 +548,8 @@ static int cx24123_pll_calculate(struct dvb_frontend *fe,
* FILTUNE programming bits */
for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) {
agcv = &cx24123_AGC_vals[i];
- if ((agcv->symbolrate_low <= p->u.qpsk.symbol_rate) &&
- (agcv->symbolrate_high >= p->u.qpsk.symbol_rate)) {
+ if ((agcv->symbolrate_low <= p->symbol_rate) &&
+ (agcv->symbolrate_high >= p->symbol_rate)) {
state->VCAarg = agcv->VCAprogdata;
state->VGAarg = agcv->VGAprogdata;
state->FILTune = agcv->FILTune;
@@ -601,8 +601,7 @@ static int cx24123_pll_calculate(struct dvb_frontend *fe,
* Tuner cx24109 is written through a dedicated 3wire interface
* on the demod chip.
*/
-static int cx24123_pll_writereg(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p, u32 data)
+static int cx24123_pll_writereg(struct dvb_frontend *fe, u32 data)
{
struct cx24123_state *state = fe->demodulator_priv;
unsigned long timeout;
@@ -659,26 +658,26 @@ static int cx24123_pll_writereg(struct dvb_frontend *fe,
return 0;
}
-static int cx24123_pll_tune(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int cx24123_pll_tune(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
dprintk("frequency=%i\n", p->frequency);
- if (cx24123_pll_calculate(fe, p) != 0) {
+ if (cx24123_pll_calculate(fe) != 0) {
err("%s: cx24123_pll_calcutate failed\n", __func__);
return -EINVAL;
}
/* Write the new VCO/VGA */
- cx24123_pll_writereg(fe, p, state->VCAarg);
- cx24123_pll_writereg(fe, p, state->VGAarg);
+ cx24123_pll_writereg(fe, state->VCAarg);
+ cx24123_pll_writereg(fe, state->VGAarg);
/* Write the new bandselect and pll args */
- cx24123_pll_writereg(fe, p, state->bandselectarg);
- cx24123_pll_writereg(fe, p, state->pllarg);
+ cx24123_pll_writereg(fe, state->bandselectarg);
+ cx24123_pll_writereg(fe, state->pllarg);
/* set the FILTUNE voltage */
val = cx24123_readreg(state, 0x28) & ~0x3;
@@ -925,10 +924,10 @@ static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr)
return 0;
}
-static int cx24123_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int cx24123_set_frontend(struct dvb_frontend *fe)
{
struct cx24123_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
dprintk("\n");
@@ -936,16 +935,16 @@ static int cx24123_set_frontend(struct dvb_frontend *fe,
state->config->set_ts_params(fe, 0);
state->currentfreq = p->frequency;
- state->currentsymbolrate = p->u.qpsk.symbol_rate;
+ state->currentsymbolrate = p->symbol_rate;
cx24123_set_inversion(state, p->inversion);
- cx24123_set_fec(state, p->u.qpsk.fec_inner);
- cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate);
+ cx24123_set_fec(state, p->fec_inner);
+ cx24123_set_symbolrate(state, p->symbol_rate);
if (!state->config->dont_use_pll)
- cx24123_pll_tune(fe, p);
+ cx24123_pll_tune(fe);
else if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
else
err("it seems I don't have a tuner...");
@@ -960,9 +959,9 @@ static int cx24123_set_frontend(struct dvb_frontend *fe,
return 0;
}
-static int cx24123_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int cx24123_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct cx24123_state *state = fe->demodulator_priv;
dprintk("\n");
@@ -971,12 +970,12 @@ static int cx24123_get_frontend(struct dvb_frontend *fe,
err("%s: Failed to get inversion status\n", __func__);
return -EREMOTEIO;
}
- if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) {
+ if (cx24123_get_fec(state, &p->fec_inner) != 0) {
err("%s: Failed to get fec status\n", __func__);
return -EREMOTEIO;
}
p->frequency = state->currentfreq;
- p->u.qpsk.symbol_rate = state->currentsymbolrate;
+ p->symbol_rate = state->currentsymbolrate;
return 0;
}
@@ -1007,15 +1006,15 @@ static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
}
static int cx24123_tune(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
+ bool re_tune,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status)
{
int retval = 0;
- if (params != NULL)
- retval = cx24123_set_frontend(fe, params);
+ if (re_tune)
+ retval = cx24123_set_frontend(fe);
if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
cx24123_read_status(fe, status);
@@ -1126,10 +1125,9 @@ error:
EXPORT_SYMBOL(cx24123_attach);
static struct dvb_frontend_ops cx24123_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "Conexant CX24123/CX24109",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1011, /* kHz for QPSK frontends */
diff --git a/drivers/media/dvb/frontends/cxd2820r.h b/drivers/media/dvb/frontends/cxd2820r.h
index 03cab7b547fb..5aa306ebb7ef 100644
--- a/drivers/media/dvb/frontends/cxd2820r.h
+++ b/drivers/media/dvb/frontends/cxd2820r.h
@@ -63,19 +63,6 @@ struct cxd2820r_config {
*/
bool spec_inv;
- /* IFs for all used modes.
- * Default: none, must set
- * Values: <kHz>
- */
- u16 if_dvbt_6;
- u16 if_dvbt_7;
- u16 if_dvbt_8;
- u16 if_dvbt2_5;
- u16 if_dvbt2_6;
- u16 if_dvbt2_7;
- u16 if_dvbt2_8;
- u16 if_dvbc;
-
/* GPIOs for all used modes.
* Default: none, disabled
* Values: <see above>
@@ -90,14 +77,12 @@ struct cxd2820r_config {
(defined(CONFIG_DVB_CXD2820R_MODULE) && defined(MODULE))
extern struct dvb_frontend *cxd2820r_attach(
const struct cxd2820r_config *config,
- struct i2c_adapter *i2c,
- struct dvb_frontend *fe
+ struct i2c_adapter *i2c
);
#else
static inline struct dvb_frontend *cxd2820r_attach(
const struct cxd2820r_config *config,
- struct i2c_adapter *i2c,
- struct dvb_frontend *fe
+ struct i2c_adapter *i2c
)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
diff --git a/drivers/media/dvb/frontends/cxd2820r_c.c b/drivers/media/dvb/frontends/cxd2820r_c.c
index b85f5011e344..945404991529 100644
--- a/drivers/media/dvb/frontends/cxd2820r_c.c
+++ b/drivers/media/dvb/frontends/cxd2820r_c.c
@@ -21,13 +21,13 @@
#include "cxd2820r_priv.h"
-int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
u8 buf[2];
+ u32 if_freq;
u16 if_ctl;
u64 num;
struct reg_val_mask tab[] = {
@@ -56,9 +56,9 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
/* program tuner */
if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, params);
+ fe->ops.tuner_ops.set_params(fe);
- if (priv->delivery_system != SYS_DVBC_ANNEX_AC) {
+ if (priv->delivery_system != SYS_DVBC_ANNEX_A) {
for (i = 0; i < ARRAY_SIZE(tab); i++) {
ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
tab[i].val, tab[i].mask);
@@ -67,10 +67,20 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
}
}
- priv->delivery_system = SYS_DVBC_ANNEX_AC;
+ priv->delivery_system = SYS_DVBC_ANNEX_A;
priv->ber_running = 0; /* tune stops BER counter */
- num = priv->cfg.if_dvbc;
+ /* program IF frequency */
+ if (fe->ops.tuner_ops.get_if_frequency) {
+ ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+ if (ret)
+ goto error;
+ } else
+ if_freq = 0;
+
+ dbg("%s: if_freq=%d", __func__, if_freq);
+
+ num = if_freq / 1000; /* Hz => kHz */
num *= 0x4000;
if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
buf[0] = (if_ctl >> 8) & 0x3f;
@@ -94,8 +104,7 @@ error:
return ret;
}
-int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c
index 036480f967b7..5c7c2aaf9bf5 100644
--- a/drivers/media/dvb/frontends/cxd2820r_core.c
+++ b/drivers/media/dvb/frontends/cxd2820r_core.c
@@ -240,422 +240,239 @@ error:
return ret;
}
-/* lock FE */
-static int cxd2820r_lock(struct cxd2820r_priv *priv, int active_fe)
-{
- int ret = 0;
- dbg("%s: active_fe=%d", __func__, active_fe);
-
- mutex_lock(&priv->fe_lock);
-
- /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
- if (priv->active_fe == active_fe)
- ;
- else if (priv->active_fe == -1)
- priv->active_fe = active_fe;
- else
- ret = -EBUSY;
-
- mutex_unlock(&priv->fe_lock);
-
- return ret;
-}
-
-/* unlock FE */
-static void cxd2820r_unlock(struct cxd2820r_priv *priv, int active_fe)
-{
- dbg("%s: active_fe=%d", __func__, active_fe);
-
- mutex_lock(&priv->fe_lock);
-
- /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
- if (priv->active_fe == active_fe)
- priv->active_fe = -1;
-
- mutex_unlock(&priv->fe_lock);
-
- return;
-}
-
/* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */
u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor)
{
return div_u64(dividend + (divisor / 2), divisor);
}
-static int cxd2820r_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int cxd2820r_set_frontend(struct dvb_frontend *fe)
{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
- dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
- if (fe->ops.info.type == FE_OFDM) {
- /* DVB-T/T2 */
- ret = cxd2820r_lock(priv, 0);
- if (ret)
- return ret;
-
- switch (priv->delivery_system) {
- case SYS_UNDEFINED:
- if (c->delivery_system == SYS_DVBT) {
- /* SLEEP => DVB-T */
- ret = cxd2820r_set_frontend_t(fe, p);
- } else {
- /* SLEEP => DVB-T2 */
- ret = cxd2820r_set_frontend_t2(fe, p);
- }
- break;
- case SYS_DVBT:
- if (c->delivery_system == SYS_DVBT) {
- /* DVB-T => DVB-T */
- ret = cxd2820r_set_frontend_t(fe, p);
- } else if (c->delivery_system == SYS_DVBT2) {
- /* DVB-T => DVB-T2 */
- ret = cxd2820r_sleep_t(fe);
- if (ret)
- break;
- ret = cxd2820r_set_frontend_t2(fe, p);
- }
- break;
- case SYS_DVBT2:
- if (c->delivery_system == SYS_DVBT2) {
- /* DVB-T2 => DVB-T2 */
- ret = cxd2820r_set_frontend_t2(fe, p);
- } else if (c->delivery_system == SYS_DVBT) {
- /* DVB-T2 => DVB-T */
- ret = cxd2820r_sleep_t2(fe);
- if (ret)
- break;
- ret = cxd2820r_set_frontend_t(fe, p);
- }
- break;
- default:
- dbg("%s: error state=%d", __func__,
- priv->delivery_system);
- ret = -EINVAL;
- }
- } else {
- /* DVB-C */
- ret = cxd2820r_lock(priv, 1);
- if (ret)
- return ret;
- ret = cxd2820r_set_frontend_c(fe, p);
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_init_t(fe);
+ if (ret < 0)
+ goto err;
+ ret = cxd2820r_set_frontend_t(fe);
+ if (ret < 0)
+ goto err;
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_init_t(fe);
+ if (ret < 0)
+ goto err;
+ ret = cxd2820r_set_frontend_t2(fe);
+ if (ret < 0)
+ goto err;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ ret = cxd2820r_init_c(fe);
+ if (ret < 0)
+ goto err;
+ ret = cxd2820r_set_frontend_c(fe);
+ if (ret < 0)
+ goto err;
+ break;
+ default:
+ dbg("%s: error state=%d", __func__, fe->dtv_property_cache.delivery_system);
+ ret = -EINVAL;
+ break;
}
-
+err:
return ret;
}
-
static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
- dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
- if (fe->ops.info.type == FE_OFDM) {
- /* DVB-T/T2 */
- ret = cxd2820r_lock(priv, 0);
- if (ret)
- return ret;
-
- switch (fe->dtv_property_cache.delivery_system) {
- case SYS_DVBT:
- ret = cxd2820r_read_status_t(fe, status);
- break;
- case SYS_DVBT2:
- ret = cxd2820r_read_status_t2(fe, status);
- break;
- default:
- ret = -EINVAL;
- }
- } else {
- /* DVB-C */
- ret = cxd2820r_lock(priv, 1);
- if (ret)
- return ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_read_status_t(fe, status);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_read_status_t2(fe, status);
+ break;
+ case SYS_DVBC_ANNEX_A:
ret = cxd2820r_read_status_c(fe, status);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
-
return ret;
}
-static int cxd2820r_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int cxd2820r_get_frontend(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
- dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
- if (fe->ops.info.type == FE_OFDM) {
- /* DVB-T/T2 */
- ret = cxd2820r_lock(priv, 0);
- if (ret)
- return ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
- switch (fe->dtv_property_cache.delivery_system) {
- case SYS_DVBT:
- ret = cxd2820r_get_frontend_t(fe, p);
- break;
- case SYS_DVBT2:
- ret = cxd2820r_get_frontend_t2(fe, p);
- break;
- default:
- ret = -EINVAL;
- }
- } else {
- /* DVB-C */
- ret = cxd2820r_lock(priv, 1);
- if (ret)
- return ret;
+ if (priv->delivery_system == SYS_UNDEFINED)
+ return 0;
- ret = cxd2820r_get_frontend_c(fe, p);
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_get_frontend_t(fe);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_get_frontend_t2(fe);
+ break;
+ case SYS_DVBC_ANNEX_A:
+ ret = cxd2820r_get_frontend_c(fe);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
-
return ret;
}
static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber)
{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
- dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
- if (fe->ops.info.type == FE_OFDM) {
- /* DVB-T/T2 */
- ret = cxd2820r_lock(priv, 0);
- if (ret)
- return ret;
-
- switch (fe->dtv_property_cache.delivery_system) {
- case SYS_DVBT:
- ret = cxd2820r_read_ber_t(fe, ber);
- break;
- case SYS_DVBT2:
- ret = cxd2820r_read_ber_t2(fe, ber);
- break;
- default:
- ret = -EINVAL;
- }
- } else {
- /* DVB-C */
- ret = cxd2820r_lock(priv, 1);
- if (ret)
- return ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_read_ber_t(fe, ber);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_read_ber_t2(fe, ber);
+ break;
+ case SYS_DVBC_ANNEX_A:
ret = cxd2820r_read_ber_c(fe, ber);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
-
return ret;
}
static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
- dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
- if (fe->ops.info.type == FE_OFDM) {
- /* DVB-T/T2 */
- ret = cxd2820r_lock(priv, 0);
- if (ret)
- return ret;
-
- switch (fe->dtv_property_cache.delivery_system) {
- case SYS_DVBT:
- ret = cxd2820r_read_signal_strength_t(fe, strength);
- break;
- case SYS_DVBT2:
- ret = cxd2820r_read_signal_strength_t2(fe, strength);
- break;
- default:
- ret = -EINVAL;
- }
- } else {
- /* DVB-C */
- ret = cxd2820r_lock(priv, 1);
- if (ret)
- return ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_read_signal_strength_t(fe, strength);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_read_signal_strength_t2(fe, strength);
+ break;
+ case SYS_DVBC_ANNEX_A:
ret = cxd2820r_read_signal_strength_c(fe, strength);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
-
return ret;
}
static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr)
{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
- dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
- if (fe->ops.info.type == FE_OFDM) {
- /* DVB-T/T2 */
- ret = cxd2820r_lock(priv, 0);
- if (ret)
- return ret;
-
- switch (fe->dtv_property_cache.delivery_system) {
- case SYS_DVBT:
- ret = cxd2820r_read_snr_t(fe, snr);
- break;
- case SYS_DVBT2:
- ret = cxd2820r_read_snr_t2(fe, snr);
- break;
- default:
- ret = -EINVAL;
- }
- } else {
- /* DVB-C */
- ret = cxd2820r_lock(priv, 1);
- if (ret)
- return ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_read_snr_t(fe, snr);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_read_snr_t2(fe, snr);
+ break;
+ case SYS_DVBC_ANNEX_A:
ret = cxd2820r_read_snr_c(fe, snr);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
-
return ret;
}
static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
- dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
- if (fe->ops.info.type == FE_OFDM) {
- /* DVB-T/T2 */
- ret = cxd2820r_lock(priv, 0);
- if (ret)
- return ret;
-
- switch (fe->dtv_property_cache.delivery_system) {
- case SYS_DVBT:
- ret = cxd2820r_read_ucblocks_t(fe, ucblocks);
- break;
- case SYS_DVBT2:
- ret = cxd2820r_read_ucblocks_t2(fe, ucblocks);
- break;
- default:
- ret = -EINVAL;
- }
- } else {
- /* DVB-C */
- ret = cxd2820r_lock(priv, 1);
- if (ret)
- return ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_read_ucblocks_t(fe, ucblocks);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_read_ucblocks_t2(fe, ucblocks);
+ break;
+ case SYS_DVBC_ANNEX_A:
ret = cxd2820r_read_ucblocks_c(fe, ucblocks);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
-
return ret;
}
static int cxd2820r_init(struct dvb_frontend *fe)
{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
- int ret;
- dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
- priv->delivery_system = SYS_UNDEFINED;
- /* delivery system is unknown at that (init) phase */
-
- if (fe->ops.info.type == FE_OFDM) {
- /* DVB-T/T2 */
- ret = cxd2820r_lock(priv, 0);
- if (ret)
- return ret;
-
- ret = cxd2820r_init_t(fe);
- } else {
- /* DVB-C */
- ret = cxd2820r_lock(priv, 1);
- if (ret)
- return ret;
-
- ret = cxd2820r_init_c(fe);
- }
-
- return ret;
+ return 0;
}
static int cxd2820r_sleep(struct dvb_frontend *fe)
{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
- dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
- if (fe->ops.info.type == FE_OFDM) {
- /* DVB-T/T2 */
- ret = cxd2820r_lock(priv, 0);
- if (ret)
- return ret;
-
- switch (fe->dtv_property_cache.delivery_system) {
- case SYS_DVBT:
- ret = cxd2820r_sleep_t(fe);
- break;
- case SYS_DVBT2:
- ret = cxd2820r_sleep_t2(fe);
- break;
- default:
- ret = -EINVAL;
- }
-
- cxd2820r_unlock(priv, 0);
- } else {
- /* DVB-C */
- ret = cxd2820r_lock(priv, 1);
- if (ret)
- return ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_sleep_t(fe);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_sleep_t2(fe);
+ break;
+ case SYS_DVBC_ANNEX_A:
ret = cxd2820r_sleep_c(fe);
-
- cxd2820r_unlock(priv, 1);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
-
return ret;
}
static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
- struct dvb_frontend_tune_settings *s)
+ struct dvb_frontend_tune_settings *s)
{
- struct cxd2820r_priv *priv = fe->demodulator_priv;
int ret;
- dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
- if (fe->ops.info.type == FE_OFDM) {
- /* DVB-T/T2 */
- ret = cxd2820r_lock(priv, 0);
- if (ret)
- return ret;
-
- switch (fe->dtv_property_cache.delivery_system) {
- case SYS_DVBT:
- ret = cxd2820r_get_tune_settings_t(fe, s);
- break;
- case SYS_DVBT2:
- ret = cxd2820r_get_tune_settings_t2(fe, s);
- break;
- default:
- ret = -EINVAL;
- }
- } else {
- /* DVB-C */
- ret = cxd2820r_lock(priv, 1);
- if (ret)
- return ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_get_tune_settings_t(fe, s);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_get_tune_settings_t2(fe, s);
+ break;
+ case SYS_DVBC_ANNEX_A:
ret = cxd2820r_get_tune_settings_c(fe, s);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
-
return ret;
}
-static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -665,14 +482,23 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe,
/* switch between DVB-T and DVB-T2 when tune fails */
if (priv->last_tune_failed) {
- if (priv->delivery_system == SYS_DVBT)
+ if (priv->delivery_system == SYS_DVBT) {
+ ret = cxd2820r_sleep_t(fe);
+ if (ret)
+ goto error;
+
c->delivery_system = SYS_DVBT2;
- else
+ } else if (priv->delivery_system == SYS_DVBT2) {
+ ret = cxd2820r_sleep_t2(fe);
+ if (ret)
+ goto error;
+
c->delivery_system = SYS_DVBT;
+ }
}
/* set frontend */
- ret = cxd2820r_set_frontend(fe, p);
+ ret = cxd2820r_set_frontend(fe);
if (ret)
goto error;
@@ -680,6 +506,7 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe,
/* frontend lock wait loop count */
switch (priv->delivery_system) {
case SYS_DVBT:
+ case SYS_DVBC_ANNEX_A:
i = 20;
break;
case SYS_DVBT2:
@@ -727,9 +554,7 @@ static void cxd2820r_release(struct dvb_frontend *fe)
struct cxd2820r_priv *priv = fe->demodulator_priv;
dbg("%s", __func__);
- if (fe->ops.info.type == FE_OFDM)
- kfree(priv);
-
+ kfree(priv);
return;
}
@@ -742,128 +567,80 @@ static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1);
}
-static const struct dvb_frontend_ops cxd2820r_ops[2];
+static const struct dvb_frontend_ops cxd2820r_ops = {
+ .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A },
+ /* default: DVB-T/T2 */
+ .info = {
+ .name = "Sony CXD2820R",
+
+ .caps = FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_MUTE_TS |
+ FE_CAN_2G_MODULATION
+ },
-struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
- struct i2c_adapter *i2c, struct dvb_frontend *fe)
-{
- int ret;
- struct cxd2820r_priv *priv = NULL;
- u8 tmp;
+ .release = cxd2820r_release,
+ .init = cxd2820r_init,
+ .sleep = cxd2820r_sleep,
- if (fe == NULL) {
- /* FE0 */
- /* allocate memory for the internal priv */
- priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL);
- if (priv == NULL)
- goto error;
+ .get_tune_settings = cxd2820r_get_tune_settings,
+ .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl,
- /* setup the priv */
- priv->i2c = i2c;
- memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config));
- mutex_init(&priv->fe_lock);
+ .get_frontend = cxd2820r_get_frontend,
- priv->active_fe = -1; /* NONE */
+ .get_frontend_algo = cxd2820r_get_frontend_algo,
+ .search = cxd2820r_search,
- /* check if the demod is there */
- priv->bank[0] = priv->bank[1] = 0xff;
- ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp);
- dbg("%s: chip id=%02x", __func__, tmp);
- if (ret || tmp != 0xe1)
- goto error;
+ .read_status = cxd2820r_read_status,
+ .read_snr = cxd2820r_read_snr,
+ .read_ber = cxd2820r_read_ber,
+ .read_ucblocks = cxd2820r_read_ucblocks,
+ .read_signal_strength = cxd2820r_read_signal_strength,
+};
- /* create frontends */
- memcpy(&priv->fe[0].ops, &cxd2820r_ops[0],
- sizeof(struct dvb_frontend_ops));
- memcpy(&priv->fe[1].ops, &cxd2820r_ops[1],
- sizeof(struct dvb_frontend_ops));
+struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
+ struct i2c_adapter *i2c)
+{
+ struct cxd2820r_priv *priv = NULL;
+ int ret;
+ u8 tmp;
- priv->fe[0].demodulator_priv = priv;
- priv->fe[1].demodulator_priv = priv;
+ priv = kzalloc(sizeof (struct cxd2820r_priv), GFP_KERNEL);
+ if (!priv)
+ goto error;
- return &priv->fe[0];
+ priv->i2c = i2c;
+ memcpy(&priv->cfg, cfg, sizeof (struct cxd2820r_config));
- } else {
- /* FE1: FE0 given as pointer, just return FE1 we have
- * already created */
- priv = fe->demodulator_priv;
- return &priv->fe[1];
- }
+ priv->bank[0] = priv->bank[1] = 0xff;
+ ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp);
+ dbg("%s: chip id=%02x", __func__, tmp);
+ if (ret || tmp != 0xe1)
+ goto error;
+ memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof (struct dvb_frontend_ops));
+ priv->fe.demodulator_priv = priv;
+ return &priv->fe;
error:
kfree(priv);
return NULL;
}
EXPORT_SYMBOL(cxd2820r_attach);
-static const struct dvb_frontend_ops cxd2820r_ops[2] = {
- {
- /* DVB-T/T2 */
- .info = {
- .name = "Sony CXD2820R (DVB-T/T2)",
- .type = FE_OFDM,
- .caps =
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
- FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
- FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 |
- FE_CAN_QAM_64 | FE_CAN_QAM_256 |
- FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO |
- FE_CAN_MUTE_TS |
- FE_CAN_2G_MODULATION
- },
-
- .release = cxd2820r_release,
- .init = cxd2820r_init,
- .sleep = cxd2820r_sleep,
-
- .get_tune_settings = cxd2820r_get_tune_settings,
- .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl,
-
- .get_frontend = cxd2820r_get_frontend,
-
- .get_frontend_algo = cxd2820r_get_frontend_algo,
- .search = cxd2820r_search,
-
- .read_status = cxd2820r_read_status,
- .read_snr = cxd2820r_read_snr,
- .read_ber = cxd2820r_read_ber,
- .read_ucblocks = cxd2820r_read_ucblocks,
- .read_signal_strength = cxd2820r_read_signal_strength,
- },
- {
- /* DVB-C */
- .info = {
- .name = "Sony CXD2820R (DVB-C)",
- .type = FE_QAM,
- .caps =
- FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
- FE_CAN_QAM_128 | FE_CAN_QAM_256 |
- FE_CAN_FEC_AUTO
- },
-
- .release = cxd2820r_release,
- .init = cxd2820r_init,
- .sleep = cxd2820r_sleep,
-
- .get_tune_settings = cxd2820r_get_tune_settings,
- .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl,
-
- .set_frontend = cxd2820r_set_frontend,
- .get_frontend = cxd2820r_get_frontend,
-
- .read_status = cxd2820r_read_status,
- .read_snr = cxd2820r_read_snr,
- .read_ber = cxd2820r_read_ber,
- .read_ucblocks = cxd2820r_read_ucblocks,
- .read_signal_strength = cxd2820r_read_signal_strength,
- },
-};
-
-
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Sony CXD2820R demodulator driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb/frontends/cxd2820r_priv.h
index 95539134efdb..9a9822cad9cd 100644
--- a/drivers/media/dvb/frontends/cxd2820r_priv.h
+++ b/drivers/media/dvb/frontends/cxd2820r_priv.h
@@ -48,12 +48,9 @@ struct reg_val_mask {
struct cxd2820r_priv {
struct i2c_adapter *i2c;
- struct dvb_frontend fe[2];
+ struct dvb_frontend fe;
struct cxd2820r_config cfg;
- struct mutex fe_lock; /* FE lock */
- int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */
-
bool ber_running;
u8 bank[2];
@@ -89,11 +86,9 @@ int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val);
/* cxd2820r_c.c */
-int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p);
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe);
-int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params);
+int cxd2820r_set_frontend_c(struct dvb_frontend *fe);
int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status);
@@ -114,11 +109,9 @@ int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
/* cxd2820r_t.c */
-int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p);
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe);
-int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params);
+int cxd2820r_set_frontend_t(struct dvb_frontend *fe);
int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status);
@@ -139,11 +132,9 @@ int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
/* cxd2820r_t2.c */
-int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p);
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe);
-int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params);
+int cxd2820r_set_frontend_t2(struct dvb_frontend *fe);
int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status);
diff --git a/drivers/media/dvb/frontends/cxd2820r_t.c b/drivers/media/dvb/frontends/cxd2820r_t.c
index a04f9c810101..1a026239cdcc 100644
--- a/drivers/media/dvb/frontends/cxd2820r_t.c
+++ b/drivers/media/dvb/frontends/cxd2820r_t.c
@@ -21,13 +21,12 @@
#include "cxd2820r_priv.h"
-int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+int cxd2820r_set_frontend_t(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int ret, i;
- u32 if_khz, if_ctl;
+ int ret, i, bw_i;
+ u32 if_freq, if_ctl;
u64 num;
u8 buf[3], bw_param;
u8 bw_params1[][5] = {
@@ -57,6 +56,23 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
+ switch (c->bandwidth_hz) {
+ case 6000000:
+ bw_i = 0;
+ bw_param = 2;
+ break;
+ case 7000000:
+ bw_i = 1;
+ bw_param = 1;
+ break;
+ case 8000000:
+ bw_i = 2;
+ bw_param = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
/* update GPIOs */
ret = cxd2820r_gpio(fe);
if (ret)
@@ -64,7 +80,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
/* program tuner */
if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (priv->delivery_system != SYS_DVBT) {
for (i = 0; i < ARRAY_SIZE(tab); i++) {
@@ -78,27 +94,17 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
priv->delivery_system = SYS_DVBT;
priv->ber_running = 0; /* tune stops BER counter */
- switch (c->bandwidth_hz) {
- case 6000000:
- if_khz = priv->cfg.if_dvbt_6;
- i = 0;
- bw_param = 2;
- break;
- case 7000000:
- if_khz = priv->cfg.if_dvbt_7;
- i = 1;
- bw_param = 1;
- break;
- case 8000000:
- if_khz = priv->cfg.if_dvbt_8;
- i = 2;
- bw_param = 0;
- break;
- default:
- return -EINVAL;
- }
+ /* program IF frequency */
+ if (fe->ops.tuner_ops.get_if_frequency) {
+ ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+ if (ret)
+ goto error;
+ } else
+ if_freq = 0;
+
+ dbg("%s: if_freq=%d", __func__, if_freq);
- num = if_khz;
+ num = if_freq / 1000; /* Hz => kHz */
num *= 0x1000000;
if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
buf[0] = ((if_ctl >> 16) & 0xff);
@@ -109,7 +115,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
if (ret)
goto error;
- ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[i], 5);
+ ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[bw_i], 5);
if (ret)
goto error;
@@ -117,7 +123,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
if (ret)
goto error;
- ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[i], 2);
+ ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[bw_i], 2);
if (ret)
goto error;
@@ -135,8 +141,7 @@ error:
return ret;
}
-int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
diff --git a/drivers/media/dvb/frontends/cxd2820r_t2.c b/drivers/media/dvb/frontends/cxd2820r_t2.c
index 6548588309f7..3a5759e0d235 100644
--- a/drivers/media/dvb/frontends/cxd2820r_t2.c
+++ b/drivers/media/dvb/frontends/cxd2820r_t2.c
@@ -21,13 +21,12 @@
#include "cxd2820r_priv.h"
-int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+int cxd2820r_set_frontend_t2(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int ret, i;
- u32 if_khz, if_ctl;
+ int ret, i, bw_i;
+ u32 if_freq, if_ctl;
u64 num;
u8 buf[3], bw_param;
u8 bw_params1[][5] = {
@@ -71,6 +70,27 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
+ switch (c->bandwidth_hz) {
+ case 5000000:
+ bw_i = 0;
+ bw_param = 3;
+ break;
+ case 6000000:
+ bw_i = 1;
+ bw_param = 2;
+ break;
+ case 7000000:
+ bw_i = 2;
+ bw_param = 1;
+ break;
+ case 8000000:
+ bw_i = 3;
+ bw_param = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
/* update GPIOs */
ret = cxd2820r_gpio(fe);
if (ret)
@@ -78,7 +98,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
/* program tuner */
if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, params);
+ fe->ops.tuner_ops.set_params(fe);
if (priv->delivery_system != SYS_DVBT2) {
for (i = 0; i < ARRAY_SIZE(tab); i++) {
@@ -91,32 +111,17 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
priv->delivery_system = SYS_DVBT2;
- switch (c->bandwidth_hz) {
- case 5000000:
- if_khz = priv->cfg.if_dvbt2_5;
- i = 0;
- bw_param = 3;
- break;
- case 6000000:
- if_khz = priv->cfg.if_dvbt2_6;
- i = 1;
- bw_param = 2;
- break;
- case 7000000:
- if_khz = priv->cfg.if_dvbt2_7;
- i = 2;
- bw_param = 1;
- break;
- case 8000000:
- if_khz = priv->cfg.if_dvbt2_8;
- i = 3;
- bw_param = 0;
- break;
- default:
- return -EINVAL;
- }
+ /* program IF frequency */
+ if (fe->ops.tuner_ops.get_if_frequency) {
+ ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+ if (ret)
+ goto error;
+ } else
+ if_freq = 0;
+
+ dbg("%s: if_freq=%d", __func__, if_freq);
- num = if_khz;
+ num = if_freq / 1000; /* Hz => kHz */
num *= 0x1000000;
if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
buf[0] = ((if_ctl >> 16) & 0xff);
@@ -127,7 +132,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
if (ret)
goto error;
- ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[i], 5);
+ ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[bw_i], 5);
if (ret)
goto error;
@@ -150,8 +155,7 @@ error:
}
-int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe)
{
struct cxd2820r_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
index dc1cb17a6ea7..3b024bfe980a 100644
--- a/drivers/media/dvb/frontends/dib0070.c
+++ b/drivers/media/dvb/frontends/dib0070.c
@@ -150,7 +150,7 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
} \
} while (0)
-static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+static int dib0070_set_bandwidth(struct dvb_frontend *fe)
{
struct dib0070_state *state = fe->tuner_priv;
u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
@@ -335,7 +335,7 @@ static const struct dib0070_lna_match dib0070_lna[] = {
};
#define LPF 100
-static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+static int dib0070_tune_digital(struct dvb_frontend *fe)
{
struct dib0070_state *state = fe->tuner_priv;
@@ -507,7 +507,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par
*tune_state = CT_TUNER_STEP_5;
} else if (*tune_state == CT_TUNER_STEP_5) {
- dib0070_set_bandwidth(fe, ch);
+ dib0070_set_bandwidth(fe);
*tune_state = CT_TUNER_STOP;
} else {
ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
@@ -516,7 +516,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par
}
-static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dib0070_tune(struct dvb_frontend *fe)
{
struct dib0070_state *state = fe->tuner_priv;
uint32_t ret;
@@ -524,7 +524,7 @@ static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters
state->tune_state = CT_TUNER_START;
do {
- ret = dib0070_tune_digital(fe, p);
+ ret = dib0070_tune_digital(fe);
if (ret != FE_CALLBACK_TIME_NEVER)
msleep(ret/10);
else
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c
index b174d1c78583..d9fe60b4be48 100644
--- a/drivers/media/dvb/frontends/dib0090.c
+++ b/drivers/media/dvb/frontends/dib0090.c
@@ -519,7 +519,7 @@ static int dib0090_fw_identify(struct dvb_frontend *fe)
return 0;
identification_error:
- return -EIO;;
+ return -EIO;
}
static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
@@ -717,6 +717,34 @@ static const u16 rf_ramp_pwm_cband_7090[] = {
(0 << 10) | 109, /* RF_RAMP4, LNA 4 */
};
+static const uint16_t rf_ramp_pwm_cband_7090e_sensitivity[] = {
+ 186,
+ 40,
+ 746,
+ (10 << 10) | 345,
+ (0 << 10) | 746,
+ (0 << 10) | 0,
+ (0 << 10) | 0,
+ (28 << 10) | 200,
+ (0 << 10) | 345,
+ (20 << 10) | 0,
+ (0 << 10) | 200,
+};
+
+static const uint16_t rf_ramp_pwm_cband_7090e_aci[] = {
+ 86,
+ 40,
+ 345,
+ (0 << 10) | 0,
+ (0 << 10) | 0,
+ (0 << 10) | 0,
+ (0 << 10) | 0,
+ (28 << 10) | 200,
+ (0 << 10) | 345,
+ (20 << 10) | 0,
+ (0 << 10) | 200,
+};
+
static const u16 rf_ramp_pwm_cband_8090[] = {
345, /* max RF gain in 10th of dB */
29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
@@ -1076,8 +1104,16 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
- else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
+ else if (state->identity.version == SOC_7090_P1G_11R1
+ || state->identity.version == SOC_7090_P1G_21R1) {
+ if (state->config->is_dib7090e) {
+ if (state->rf_ramp == NULL)
+ dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090e_sensitivity);
+ else
+ dib0090_set_rframp_pwm(state, state->rf_ramp);
+ } else
+ dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
+ }
} else {
dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
@@ -1112,13 +1148,21 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
else
dib0090_write_reg(state, 0x32, (0 << 11));
- dib0090_write_reg(state, 0x04, 0x01);
+ dib0090_write_reg(state, 0x04, 0x03);
dib0090_write_reg(state, 0x39, (1 << 10));
}
}
EXPORT_SYMBOL(dib0090_pwm_gain_reset);
+void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
+{
+ struct dib0090_state *state = fe->tuner_priv;
+ if (DC_servo_cutoff < 4)
+ dib0090_write_reg(state, 0x04, DC_servo_cutoff);
+}
+EXPORT_SYMBOL(dib0090_set_dc_servo);
+
static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
{
u16 adc_val = dib0090_read_reg(state, 0x1d);
@@ -1305,7 +1349,7 @@ void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 *
EXPORT_SYMBOL(dib0090_get_current_gain);
-u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
+u16 dib0090_get_wbd_target(struct dvb_frontend *fe)
{
struct dib0090_state *state = fe->tuner_priv;
u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
@@ -1342,9 +1386,57 @@ u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
return state->wbd_offset + wbd_tcold;
}
+EXPORT_SYMBOL(dib0090_get_wbd_target);
+u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
+{
+ struct dib0090_state *state = fe->tuner_priv;
+ return state->wbd_offset;
+}
EXPORT_SYMBOL(dib0090_get_wbd_offset);
+int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3)
+{
+ struct dib0090_state *state = fe->tuner_priv;
+
+ dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xfff8)
+ | ((sw3 & 1) << 2) | ((sw2 & 1) << 1) | (sw1 & 1));
+
+ return 0;
+}
+EXPORT_SYMBOL(dib0090_set_switch);
+
+int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
+{
+ struct dib0090_state *state = fe->tuner_priv;
+
+ dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x7fff)
+ | ((onoff & 1) << 15));
+ return 0;
+}
+EXPORT_SYMBOL(dib0090_set_vga);
+
+int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity)
+{
+ struct dib0090_state *state = fe->tuner_priv;
+
+ if ((!state->identity.p1g) || (!state->identity.in_soc)
+ || ((state->identity.version != SOC_7090_P1G_21R1)
+ && (state->identity.version != SOC_7090_P1G_11R1))) {
+ dprintk("%s() function can only be used for dib7090P", __func__);
+ return -ENODEV;
+ }
+
+ if (cfg_sensitivity)
+ state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
+ else
+ state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_aci;
+ dib0090_pwm_gain_reset(fe);
+
+ return 0;
+}
+EXPORT_SYMBOL(dib0090_update_rframp_7090);
+
static const u16 dib0090_defaults[] = {
25, 0x01,
@@ -1430,7 +1522,7 @@ static void dib0090_set_default_config(struct dib0090_state *state, const u16 *
#define POLY_MIN (u8) 0
#define POLY_MAX (u8) 8
-void dib0090_set_EFUSE(struct dib0090_state *state)
+static void dib0090_set_EFUSE(struct dib0090_state *state)
{
u8 c, h, n;
u16 e2, e4;
@@ -1505,7 +1597,10 @@ static int dib0090_reset(struct dvb_frontend *fe)
dib0090_set_EFUSE(state);
/* Congigure in function of the crystal */
- if (state->config->io.clock_khz >= 24000)
+ if (state->config->force_crystal_mode != 0)
+ dib0090_write_reg(state, 0x14,
+ state->config->force_crystal_mode & 3);
+ else if (state->config->io.clock_khz >= 24000)
dib0090_write_reg(state, 0x14, 1);
else
dib0090_write_reg(state, 0x14, 2);
@@ -1951,6 +2046,52 @@ static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
#endif
};
+static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_sensitivity[] = {
+#ifdef CONFIG_BAND_CBAND
+ { 300000, 0 , 3, 0x8105, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
+ { 380000, 0 , 10, 0x810F, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
+ { 600000, 0 , 10, 0x815E, 0x280, 0x2d12, 0xb84e, EN_CAB },
+ { 660000, 0 , 5, 0x85E3, 0x280, 0x2d12, 0xb84e, EN_CAB },
+ { 720000, 0 , 5, 0x852E, 0x280, 0x2d12, 0xb84e, EN_CAB },
+ { 860000, 0 , 4, 0x85E5, 0x280, 0x2d12, 0xb84e, EN_CAB },
+#endif
+};
+
+int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
+ u8 cfg_sensitivity)
+{
+ struct dib0090_state *state = fe->tuner_priv;
+ const struct dib0090_tuning *tune =
+ dib0090_tuning_table_cband_7090e_sensitivity;
+ const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = {
+ { 300000, 0 , 3, 0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
+ { 650000, 0 , 4, 0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB },
+ { 860000, 0 , 5, 0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB },
+ };
+
+ if ((!state->identity.p1g) || (!state->identity.in_soc)
+ || ((state->identity.version != SOC_7090_P1G_21R1)
+ && (state->identity.version != SOC_7090_P1G_11R1))) {
+ dprintk("%s() function can only be used for dib7090", __func__);
+ return -ENODEV;
+ }
+
+ if (cfg_sensitivity)
+ tune = dib0090_tuning_table_cband_7090e_sensitivity;
+ else
+ tune = dib0090_tuning_table_cband_7090e_aci;
+
+ while (state->rf_request > tune->max_freq)
+ tune++;
+
+ dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x8000)
+ | (tune->lna_bias & 0x7fff));
+ dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xf83f)
+ | ((tune->lna_tune << 6) & 0x07c0));
+ return 0;
+}
+EXPORT_SYMBOL(dib0090_update_tuning_table_7090);
+
static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
{
int ret = 0;
@@ -2199,12 +2340,18 @@ static int dib0090_tune(struct dvb_frontend *fe)
if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
|| state->current_band & BAND_UHF) {
state->current_band = BAND_CBAND;
- tune = dib0090_tuning_table_cband_7090;
+ if (state->config->is_dib7090e)
+ tune = dib0090_tuning_table_cband_7090e_sensitivity;
+ else
+ tune = dib0090_tuning_table_cband_7090;
}
} else { /* Use the CBAND input for all band under UHF */
if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
state->current_band = BAND_CBAND;
- tune = dib0090_tuning_table_cband_7090;
+ if (state->config->is_dib7090e)
+ tune = dib0090_tuning_table_cband_7090e_sensitivity;
+ else
+ tune = dib0090_tuning_table_cband_7090;
}
}
} else
@@ -2419,7 +2566,7 @@ static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
return 0;
}
-static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dib0090_set_params(struct dvb_frontend *fe)
{
struct dib0090_state *state = fe->tuner_priv;
u32 ret;
diff --git a/drivers/media/dvb/frontends/dib0090.h b/drivers/media/dvb/frontends/dib0090.h
index 13d85244ec16..781dc49de45b 100644
--- a/drivers/media/dvb/frontends/dib0090.h
+++ b/drivers/media/dvb/frontends/dib0090.h
@@ -71,6 +71,8 @@ struct dib0090_config {
u8 fref_clock_ratio;
u16 force_cband_input;
struct dib0090_wbd_slope *wbd;
+ u8 is_dib7090e;
+ u8 force_crystal_mode;
};
#if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE))
@@ -78,13 +80,21 @@ extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c
extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast);
extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe);
-extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner);
+extern u16 dib0090_get_wbd_target(struct dvb_frontend *tuner);
+extern u16 dib0090_get_wbd_offset(struct dvb_frontend *fe);
extern int dib0090_gain_control(struct dvb_frontend *fe);
extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe);
extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt);
+extern void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff);
+extern int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3);
+extern int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff);
+extern int dib0090_update_rframp_7090(struct dvb_frontend *fe,
+ u8 cfg_sensitivity);
+extern int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
+ u8 cfg_sensitivity);
#else
-static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config)
+static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
@@ -106,7 +116,13 @@ static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
}
-static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner)
+static inline u16 dib0090_get_wbd_target(struct dvb_frontend *tuner)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return 0;
+}
+
+static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return 0;
@@ -134,6 +150,38 @@ static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
}
+
+static inline void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline int dib0090_set_switch(struct dvb_frontend *fe,
+ u8 sw1, u8 sw2, u8 sw3)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
+
+static inline int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
+
+static inline int dib0090_update_rframp_7090(struct dvb_frontend *fe,
+ u8 cfg_sensitivity)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
+
+static inline int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
+ u8 cfg_sensitivity)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
#endif
#endif
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index 437904cbf3e6..af91e0c92339 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -112,39 +112,37 @@ static u16 dib3000_seq[2][2][2] = /* fft,gua, inv */
}
};
-static int dib3000mb_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep);
+static int dib3000mb_get_frontend(struct dvb_frontend* fe);
-static int dib3000mb_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep, int tuner)
+static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner)
{
struct dib3000_state* state = fe->demodulator_priv;
- struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
fe_code_rate_t fe_cr = FEC_NONE;
int search_state, seq;
if (tuner && fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, fep);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
deb_setf("bandwidth: ");
- switch (ofdm->bandwidth) {
- case BANDWIDTH_8_MHZ:
+ switch (c->bandwidth_hz) {
+ case 8000000:
deb_setf("8 MHz\n");
wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]);
wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz);
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
deb_setf("7 MHz\n");
wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]);
wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz);
break;
- case BANDWIDTH_6_MHZ:
+ case 6000000:
deb_setf("6 MHz\n");
wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]);
wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz);
break;
- case BANDWIDTH_AUTO:
+ case 0:
return -EOPNOTSUPP;
default:
err("unknown bandwidth value.");
@@ -154,7 +152,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4);
deb_setf("transmission mode: ");
- switch (ofdm->transmission_mode) {
+ switch (c->transmission_mode) {
case TRANSMISSION_MODE_2K:
deb_setf("2k\n");
wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K);
@@ -171,7 +169,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
}
deb_setf("guard: ");
- switch (ofdm->guard_interval) {
+ switch (c->guard_interval) {
case GUARD_INTERVAL_1_32:
deb_setf("1_32\n");
wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32);
@@ -196,7 +194,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
}
deb_setf("inversion: ");
- switch (fep->inversion) {
+ switch (c->inversion) {
case INVERSION_OFF:
deb_setf("off\n");
wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF);
@@ -212,8 +210,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
return -EINVAL;
}
- deb_setf("constellation: ");
- switch (ofdm->constellation) {
+ deb_setf("modulation: ");
+ switch (c->modulation) {
case QPSK:
deb_setf("qpsk\n");
wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK);
@@ -232,7 +230,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
return -EINVAL;
}
deb_setf("hierarchy: ");
- switch (ofdm->hierarchy_information) {
+ switch (c->hierarchy) {
case HIERARCHY_NONE:
deb_setf("none ");
/* fall through */
@@ -256,16 +254,16 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
}
deb_setf("hierarchy: ");
- if (ofdm->hierarchy_information == HIERARCHY_NONE) {
+ if (c->hierarchy == HIERARCHY_NONE) {
deb_setf("none\n");
wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF);
wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP);
- fe_cr = ofdm->code_rate_HP;
- } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
+ fe_cr = c->code_rate_HP;
+ } else if (c->hierarchy != HIERARCHY_AUTO) {
deb_setf("on\n");
wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON);
wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP);
- fe_cr = ofdm->code_rate_LP;
+ fe_cr = c->code_rate_LP;
}
deb_setf("fec: ");
switch (fe_cr) {
@@ -300,9 +298,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
}
seq = dib3000_seq
- [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
- [ofdm->guard_interval == GUARD_INTERVAL_AUTO]
- [fep->inversion == INVERSION_AUTO];
+ [c->transmission_mode == TRANSMISSION_MODE_AUTO]
+ [c->guard_interval == GUARD_INTERVAL_AUTO]
+ [c->inversion == INVERSION_AUTO];
deb_setf("seq? %d\n", seq);
@@ -310,8 +308,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE);
- if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) {
- if (ofdm->guard_interval == GUARD_INTERVAL_1_8) {
+ if (c->transmission_mode == TRANSMISSION_MODE_2K) {
+ if (c->guard_interval == GUARD_INTERVAL_1_8) {
wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8);
} else {
wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT);
@@ -339,10 +337,10 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low);
/* something has to be auto searched */
- if (ofdm->constellation == QAM_AUTO ||
- ofdm->hierarchy_information == HIERARCHY_AUTO ||
+ if (c->modulation == QAM_AUTO ||
+ c->hierarchy == HIERARCHY_AUTO ||
fe_cr == FEC_AUTO ||
- fep->inversion == INVERSION_AUTO) {
+ c->inversion == INVERSION_AUTO) {
int as_count=0;
deb_setf("autosearch enabled.\n");
@@ -361,10 +359,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count);
if (search_state == 1) {
- struct dvb_frontend_parameters feps;
- if (dib3000mb_get_frontend(fe, &feps) == 0) {
+ if (dib3000mb_get_frontend(fe) == 0) {
deb_setf("reading tuning data from frontend succeeded.\n");
- return dib3000mb_set_frontend(fe, &feps, 0);
+ return dib3000mb_set_frontend(fe, 0);
}
}
@@ -453,11 +450,10 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
return 0;
}
-static int dib3000mb_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static int dib3000mb_get_frontend(struct dvb_frontend* fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dib3000_state* state = fe->demodulator_priv;
- struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
fe_code_rate_t *cr;
u16 tps_val;
int inv_test1,inv_test2;
@@ -484,25 +480,25 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
else
inv_test2 = 2;
- fep->inversion =
+ c->inversion =
((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
INVERSION_ON : INVERSION_OFF;
- deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
+ deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, c->inversion);
switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) {
case DIB3000_CONSTELLATION_QPSK:
deb_getf("QPSK ");
- ofdm->constellation = QPSK;
+ c->modulation = QPSK;
break;
case DIB3000_CONSTELLATION_16QAM:
deb_getf("QAM16 ");
- ofdm->constellation = QAM_16;
+ c->modulation = QAM_16;
break;
case DIB3000_CONSTELLATION_64QAM:
deb_getf("QAM64 ");
- ofdm->constellation = QAM_64;
+ c->modulation = QAM_64;
break;
default:
err("Unexpected constellation returned by TPS (%d)", tps_val);
@@ -512,24 +508,24 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
if (rd(DIB3000MB_REG_TPS_HRCH)) {
deb_getf("HRCH ON\n");
- cr = &ofdm->code_rate_LP;
- ofdm->code_rate_HP = FEC_NONE;
+ cr = &c->code_rate_LP;
+ c->code_rate_HP = FEC_NONE;
switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) {
case DIB3000_ALPHA_0:
deb_getf("HIERARCHY_NONE ");
- ofdm->hierarchy_information = HIERARCHY_NONE;
+ c->hierarchy = HIERARCHY_NONE;
break;
case DIB3000_ALPHA_1:
deb_getf("HIERARCHY_1 ");
- ofdm->hierarchy_information = HIERARCHY_1;
+ c->hierarchy = HIERARCHY_1;
break;
case DIB3000_ALPHA_2:
deb_getf("HIERARCHY_2 ");
- ofdm->hierarchy_information = HIERARCHY_2;
+ c->hierarchy = HIERARCHY_2;
break;
case DIB3000_ALPHA_4:
deb_getf("HIERARCHY_4 ");
- ofdm->hierarchy_information = HIERARCHY_4;
+ c->hierarchy = HIERARCHY_4;
break;
default:
err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
@@ -540,9 +536,9 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
} else {
deb_getf("HRCH OFF\n");
- cr = &ofdm->code_rate_HP;
- ofdm->code_rate_LP = FEC_NONE;
- ofdm->hierarchy_information = HIERARCHY_NONE;
+ cr = &c->code_rate_HP;
+ c->code_rate_LP = FEC_NONE;
+ c->hierarchy = HIERARCHY_NONE;
tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
}
@@ -577,19 +573,19 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) {
case DIB3000_GUARD_TIME_1_32:
deb_getf("GUARD_INTERVAL_1_32 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_32;
+ c->guard_interval = GUARD_INTERVAL_1_32;
break;
case DIB3000_GUARD_TIME_1_16:
deb_getf("GUARD_INTERVAL_1_16 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_16;
+ c->guard_interval = GUARD_INTERVAL_1_16;
break;
case DIB3000_GUARD_TIME_1_8:
deb_getf("GUARD_INTERVAL_1_8 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_8;
+ c->guard_interval = GUARD_INTERVAL_1_8;
break;
case DIB3000_GUARD_TIME_1_4:
deb_getf("GUARD_INTERVAL_1_4 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_4;
+ c->guard_interval = GUARD_INTERVAL_1_4;
break;
default:
err("Unexpected Guard Time returned by TPS (%d)", tps_val);
@@ -600,11 +596,11 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) {
case DIB3000_TRANSMISSION_MODE_2K:
deb_getf("TRANSMISSION_MODE_2K ");
- ofdm->transmission_mode = TRANSMISSION_MODE_2K;
+ c->transmission_mode = TRANSMISSION_MODE_2K;
break;
case DIB3000_TRANSMISSION_MODE_8K:
deb_getf("TRANSMISSION_MODE_8K ");
- ofdm->transmission_mode = TRANSMISSION_MODE_8K;
+ c->transmission_mode = TRANSMISSION_MODE_8K;
break;
default:
err("unexpected transmission mode return by TPS (%d)", tps_val);
@@ -701,9 +697,9 @@ static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe)
return dib3000mb_fe_init(fe, 0);
}
-static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep)
+static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend *fe)
{
- return dib3000mb_set_frontend(fe, fep, 1);
+ return dib3000mb_set_frontend(fe, 1);
}
static void dib3000mb_release(struct dvb_frontend* fe)
@@ -794,10 +790,9 @@ error:
}
static struct dvb_frontend_ops dib3000mb_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "DiBcom 3000M-B DVB-T",
- .type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h
index 16c526591f36..9dc235aa44b7 100644
--- a/drivers/media/dvb/frontends/dib3000mb_priv.h
+++ b/drivers/media/dvb/frontends/dib3000mb_priv.h
@@ -98,7 +98,7 @@ struct dib3000_state {
int timing_offset;
int timing_offset_comp_done;
- fe_bandwidth_t last_tuned_bw;
+ u32 last_tuned_bw;
u32 last_tuned_freq;
};
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 088e7fadbe3d..ffad181a9692 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -40,7 +40,7 @@ struct dib3000mc_state {
u32 timf;
- fe_bandwidth_t current_bandwidth;
+ u32 current_bandwidth;
u16 dev_id;
@@ -438,11 +438,14 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
dib3000mc_write_word(state, reg, cfg[reg - 129]);
}
-static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq)
+static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state,
+ struct dtv_frontend_properties *ch, u16 seq)
{
u16 value;
- dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
- dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0);
+ u32 bw = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
+
+ dib3000mc_set_bandwidth(state, bw);
+ dib3000mc_set_timing(state, ch->transmission_mode, bw, 0);
// if (boost)
// dib3000mc_write_word(state, 100, (11 << 6) + 6);
@@ -471,22 +474,22 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_
dib3000mc_write_word(state, 97,0);
dib3000mc_write_word(state, 98,0);
- dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode);
+ dib3000mc_set_impulse_noise(state, 0, ch->transmission_mode);
value = 0;
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
default:
case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
}
- switch (ch->u.ofdm.guard_interval) {
+ switch (ch->guard_interval) {
case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
default:
case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
}
- switch (ch->u.ofdm.constellation) {
+ switch (ch->modulation) {
case QPSK: value |= (0 << 3); break;
case QAM_16: value |= (1 << 3); break;
default:
@@ -502,11 +505,11 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_
dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
value = 0;
- if (ch->u.ofdm.hierarchy_information == 1)
+ if (ch->hierarchy == 1)
value |= (1 << 4);
if (1 == 1)
value |= 1;
- switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
case FEC_2_3: value |= (2 << 1); break;
case FEC_3_4: value |= (3 << 1); break;
case FEC_5_6: value |= (5 << 1); break;
@@ -517,12 +520,12 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_
dib3000mc_write_word(state, 181, value);
// diversity synchro delay add 50% SFN margin
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_8K: value = 256; break;
case TRANSMISSION_MODE_2K:
default: value = 64; break;
}
- switch (ch->u.ofdm.guard_interval) {
+ switch (ch->guard_interval) {
case GUARD_INTERVAL_1_16: value *= 2; break;
case GUARD_INTERVAL_1_8: value *= 4; break;
case GUARD_INTERVAL_1_4: value *= 8; break;
@@ -540,27 +543,28 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_
msleep(30);
- dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode);
+ dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->transmission_mode);
}
-static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan)
+static int dib3000mc_autosearch_start(struct dvb_frontend *demod)
{
+ struct dtv_frontend_properties *chan = &demod->dtv_property_cache;
struct dib3000mc_state *state = demod->demodulator_priv;
u16 reg;
// u32 val;
- struct dvb_frontend_parameters schan;
+ struct dtv_frontend_properties schan;
schan = *chan;
/* TODO what is that ? */
/* a channel for autosearch */
- schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
- schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
- schan.u.ofdm.constellation = QAM_64;
- schan.u.ofdm.code_rate_HP = FEC_2_3;
- schan.u.ofdm.code_rate_LP = FEC_2_3;
- schan.u.ofdm.hierarchy_information = 0;
+ schan.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.guard_interval = GUARD_INTERVAL_1_32;
+ schan.modulation = QAM_64;
+ schan.code_rate_HP = FEC_2_3;
+ schan.code_rate_LP = FEC_2_3;
+ schan.hierarchy = 0;
dib3000mc_set_channel_cfg(state, &schan, 11);
@@ -586,8 +590,9 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
return 0; // still pending
}
-static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib3000mc_tune(struct dvb_frontend *demod)
{
+ struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
struct dib3000mc_state *state = demod->demodulator_priv;
// ** configure demod **
@@ -603,8 +608,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame
dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift
}
- dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation);
- if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) {
+ dib3000mc_set_adp_cfg(state, (u8)ch->modulation);
+ if (ch->transmission_mode == TRANSMISSION_MODE_8K) {
dib3000mc_write_word(state, 26, 38528);
dib3000mc_write_word(state, 33, 8);
} else {
@@ -613,7 +618,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame
}
if (dib3000mc_read_word(state, 509) & 0x80)
- dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1);
+ dib3000mc_set_timing(state, ch->transmission_mode,
+ BANDWIDTH_TO_KHZ(ch->bandwidth_hz), 1);
return 0;
}
@@ -626,87 +632,87 @@ struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
-static int dib3000mc_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static int dib3000mc_get_frontend(struct dvb_frontend* fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dib3000mc_state *state = fe->demodulator_priv;
u16 tps = dib3000mc_read_word(state,458);
fep->inversion = INVERSION_AUTO;
- fep->u.ofdm.bandwidth = state->current_bandwidth;
+ fep->bandwidth_hz = state->current_bandwidth;
switch ((tps >> 8) & 0x1) {
- case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
- case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
+ case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
+ case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
}
switch (tps & 0x3) {
- case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
- case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
- case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
- case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
+ case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
+ case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
+ case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
+ case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
}
switch ((tps >> 13) & 0x3) {
- case 0: fep->u.ofdm.constellation = QPSK; break;
- case 1: fep->u.ofdm.constellation = QAM_16; break;
+ case 0: fep->modulation = QPSK; break;
+ case 1: fep->modulation = QAM_16; break;
case 2:
- default: fep->u.ofdm.constellation = QAM_64; break;
+ default: fep->modulation = QAM_64; break;
}
/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
/* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
- fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ fep->hierarchy = HIERARCHY_NONE;
switch ((tps >> 5) & 0x7) {
- case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
- case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
- case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
- case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
+ case 1: fep->code_rate_HP = FEC_1_2; break;
+ case 2: fep->code_rate_HP = FEC_2_3; break;
+ case 3: fep->code_rate_HP = FEC_3_4; break;
+ case 5: fep->code_rate_HP = FEC_5_6; break;
case 7:
- default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
+ default: fep->code_rate_HP = FEC_7_8; break;
}
switch ((tps >> 2) & 0x7) {
- case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
- case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
- case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
- case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
+ case 1: fep->code_rate_LP = FEC_1_2; break;
+ case 2: fep->code_rate_LP = FEC_2_3; break;
+ case 3: fep->code_rate_LP = FEC_3_4; break;
+ case 5: fep->code_rate_LP = FEC_5_6; break;
case 7:
- default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
+ default: fep->code_rate_LP = FEC_7_8; break;
}
return 0;
}
-static int dib3000mc_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static int dib3000mc_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dib3000mc_state *state = fe->demodulator_priv;
- int ret;
+ int ret;
dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
- state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+ state->current_bandwidth = fep->bandwidth_hz;
+ dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
/* maybe the parameter has been changed */
state->sfn_workaround_active = buggy_sfn_workaround;
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, fep);
+ fe->ops.tuner_ops.set_params(fe);
msleep(100);
}
- if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
- fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
- fep->u.ofdm.constellation == QAM_AUTO ||
- fep->u.ofdm.code_rate_HP == FEC_AUTO) {
+ if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
+ fep->guard_interval == GUARD_INTERVAL_AUTO ||
+ fep->modulation == QAM_AUTO ||
+ fep->code_rate_HP == FEC_AUTO) {
int i = 1000, found;
- dib3000mc_autosearch_start(fe, fep);
+ dib3000mc_autosearch_start(fe);
do {
msleep(1);
found = dib3000mc_autosearch_is_irq(fe);
@@ -716,14 +722,14 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
if (found == 0 || found == 1)
return 0; // no channel found
- dib3000mc_get_frontend(fe, fep);
+ dib3000mc_get_frontend(fe);
}
- ret = dib3000mc_tune(fe, fep);
+ ret = dib3000mc_tune(fe);
/* make this a config parameter */
dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
- return ret;
+ return ret;
}
static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -897,9 +903,9 @@ error:
EXPORT_SYMBOL(dib3000mc_attach);
static struct dvb_frontend_ops dib3000mc_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "DiBcom 3000MC/P",
- .type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index dbb76d75c932..148bf79236fb 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -38,7 +38,7 @@ struct dib7000m_state {
u16 wbd_ref;
u8 current_band;
- fe_bandwidth_t current_bandwidth;
+ u32 current_bandwidth;
struct dibx000_agc_config *current_agc;
u32 timf;
u32 timf_default;
@@ -313,6 +313,9 @@ static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
{
u32 timf;
+ if (!bw)
+ bw = 8000;
+
// store the current bandwidth for later use
state->current_bandwidth = bw;
@@ -742,8 +745,9 @@ static void dib7000m_update_timf(struct dib7000m_state *state)
dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default);
}
-static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000m_agc_startup(struct dvb_frontend *demod)
{
+ struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
struct dib7000m_state *state = demod->demodulator_priv;
u16 cfg_72 = dib7000m_read_word(state, 72);
int ret = -1;
@@ -832,28 +836,29 @@ static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_
return ret;
}
-static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq)
+static void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch,
+ u8 seq)
{
u16 value, est[4];
- dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
/* nfft, guard, qam, alpha */
value = 0;
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
default:
case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
}
- switch (ch->u.ofdm.guard_interval) {
+ switch (ch->guard_interval) {
case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
default:
case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
}
- switch (ch->u.ofdm.constellation) {
+ switch (ch->modulation) {
case QPSK: value |= (0 << 3); break;
case QAM_16: value |= (1 << 3); break;
default:
@@ -872,11 +877,11 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
value = 0;
if (1 != 0)
value |= (1 << 6);
- if (ch->u.ofdm.hierarchy_information == 1)
+ if (ch->hierarchy == 1)
value |= (1 << 4);
if (1 == 1)
value |= 1;
- switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
case FEC_2_3: value |= (2 << 1); break;
case FEC_3_4: value |= (3 << 1); break;
case FEC_5_6: value |= (5 << 1); break;
@@ -901,13 +906,13 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
dib7000m_write_word(state, 33, (0 << 4) | 0x5);
/* P_dvsy_sync_wait */
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_8K: value = 256; break;
case TRANSMISSION_MODE_4K: value = 128; break;
case TRANSMISSION_MODE_2K:
default: value = 64; break;
}
- switch (ch->u.ofdm.guard_interval) {
+ switch (ch->guard_interval) {
case GUARD_INTERVAL_1_16: value *= 2; break;
case GUARD_INTERVAL_1_8: value *= 4; break;
case GUARD_INTERVAL_1_4: value *= 8; break;
@@ -925,7 +930,7 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
dib7000m_set_diversity_in(&state->demod, state->div_state);
/* channel estimation fine configuration */
- switch (ch->u.ofdm.constellation) {
+ switch (ch->modulation) {
case QAM_64:
est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
@@ -952,25 +957,26 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
}
-static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000m_autosearch_start(struct dvb_frontend *demod)
{
+ struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
struct dib7000m_state *state = demod->demodulator_priv;
- struct dvb_frontend_parameters schan;
+ struct dtv_frontend_properties schan;
int ret = 0;
u32 value, factor;
schan = *ch;
- schan.u.ofdm.constellation = QAM_64;
- schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
- schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
- schan.u.ofdm.code_rate_HP = FEC_2_3;
- schan.u.ofdm.code_rate_LP = FEC_3_4;
- schan.u.ofdm.hierarchy_information = 0;
+ schan.modulation = QAM_64;
+ schan.guard_interval = GUARD_INTERVAL_1_32;
+ schan.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.code_rate_HP = FEC_2_3;
+ schan.code_rate_LP = FEC_3_4;
+ schan.hierarchy = 0;
dib7000m_set_channel(state, &schan, 7);
- factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
+ factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz);
if (factor >= 5000)
factor = 1;
else
@@ -1027,8 +1033,9 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
return dib7000m_autosearch_irq(state, 537);
}
-static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000m_tune(struct dvb_frontend *demod)
{
+ struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
struct dib7000m_state *state = demod->demodulator_priv;
int ret = 0;
u16 value;
@@ -1055,7 +1062,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
//dump_reg(state);
/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
value = (6 << 8) | 0x80;
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
case TRANSMISSION_MODE_4K: value |= (8 << 12); break;
default:
@@ -1065,7 +1072,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
value = (0 << 4);
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_2K: value |= 0x6; break;
case TRANSMISSION_MODE_4K: value |= 0x7; break;
default:
@@ -1075,7 +1082,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
value = (0 << 4);
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_2K: value |= 0x6; break;
case TRANSMISSION_MODE_4K: value |= 0x7; break;
default:
@@ -1087,7 +1094,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
if ((dib7000m_read_word(state, 535) >> 6) & 0x1)
dib7000m_update_timf(state);
- dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
return ret;
}
@@ -1147,57 +1154,57 @@ static int dib7000m_identify(struct dib7000m_state *state)
}
-static int dib7000m_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static int dib7000m_get_frontend(struct dvb_frontend* fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dib7000m_state *state = fe->demodulator_priv;
u16 tps = dib7000m_read_word(state,480);
fep->inversion = INVERSION_AUTO;
- fep->u.ofdm.bandwidth = state->current_bandwidth;
+ fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
switch ((tps >> 8) & 0x3) {
- case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
- case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
- /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
+ case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
+ case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
+ /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
}
switch (tps & 0x3) {
- case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
- case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
- case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
- case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
+ case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
+ case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
+ case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
+ case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
}
switch ((tps >> 14) & 0x3) {
- case 0: fep->u.ofdm.constellation = QPSK; break;
- case 1: fep->u.ofdm.constellation = QAM_16; break;
+ case 0: fep->modulation = QPSK; break;
+ case 1: fep->modulation = QAM_16; break;
case 2:
- default: fep->u.ofdm.constellation = QAM_64; break;
+ default: fep->modulation = QAM_64; break;
}
/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
- fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ fep->hierarchy = HIERARCHY_NONE;
switch ((tps >> 5) & 0x7) {
- case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
- case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
- case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
- case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
+ case 1: fep->code_rate_HP = FEC_1_2; break;
+ case 2: fep->code_rate_HP = FEC_2_3; break;
+ case 3: fep->code_rate_HP = FEC_3_4; break;
+ case 5: fep->code_rate_HP = FEC_5_6; break;
case 7:
- default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
+ default: fep->code_rate_HP = FEC_7_8; break;
}
switch ((tps >> 2) & 0x7) {
- case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
- case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
- case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
- case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
+ case 1: fep->code_rate_LP = FEC_1_2; break;
+ case 2: fep->code_rate_LP = FEC_2_3; break;
+ case 3: fep->code_rate_LP = FEC_3_4; break;
+ case 5: fep->code_rate_LP = FEC_5_6; break;
case 7:
- default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
+ default: fep->code_rate_LP = FEC_7_8; break;
}
/* native interleaver: (dib7000m_read_word(state, 481) >> 5) & 0x1 */
@@ -1205,35 +1212,34 @@ static int dib7000m_get_frontend(struct dvb_frontend* fe,
return 0;
}
-static int dib7000m_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static int dib7000m_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dib7000m_state *state = fe->demodulator_priv;
int time, ret;
- dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
+ dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
- state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, fep);
+ fe->ops.tuner_ops.set_params(fe);
/* start up the AGC */
state->agc_state = 0;
do {
- time = dib7000m_agc_startup(fe, fep);
+ time = dib7000m_agc_startup(fe);
if (time != -1)
msleep(time);
} while (time != -1);
- if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
- fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
- fep->u.ofdm.constellation == QAM_AUTO ||
- fep->u.ofdm.code_rate_HP == FEC_AUTO) {
+ if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
+ fep->guard_interval == GUARD_INTERVAL_AUTO ||
+ fep->modulation == QAM_AUTO ||
+ fep->code_rate_HP == FEC_AUTO) {
int i = 800, found;
- dib7000m_autosearch_start(fe, fep);
+ dib7000m_autosearch_start(fe);
do {
msleep(1);
found = dib7000m_autosearch_is_irq(fe);
@@ -1243,10 +1249,10 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
if (found == 0 || found == 1)
return 0; // no channel found
- dib7000m_get_frontend(fe, fep);
+ dib7000m_get_frontend(fe);
}
- ret = dib7000m_tune(fe, fep);
+ ret = dib7000m_tune(fe);
/* make this a config parameter */
dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
@@ -1430,9 +1436,9 @@ error:
EXPORT_SYMBOL(dib7000m_attach);
static struct dvb_frontend_ops dib7000m_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "DiBcom 7000MA/MB/PA/PB/MC",
- .type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index ce8534ff142e..5ceadc285b3a 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -70,6 +70,8 @@ struct dib7000p_state {
u8 i2c_write_buffer[4];
u8 i2c_read_buffer[2];
struct mutex i2c_buffer_lock;
+
+ u8 input_mode_mpeg;
};
enum dib7000p_power_mode {
@@ -78,8 +80,11 @@ enum dib7000p_power_mode {
DIB7000P_POWER_INTERFACE_ONLY,
};
+/* dib7090 specific fonctions */
static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
+static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
+static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
{
@@ -276,17 +281,23 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p
dib7000p_write_word(state, 774, reg_774);
dib7000p_write_word(state, 775, reg_775);
dib7000p_write_word(state, 776, reg_776);
- dib7000p_write_word(state, 899, reg_899);
dib7000p_write_word(state, 1280, reg_1280);
+ if (state->version != SOC7090)
+ dib7000p_write_word(state, 899, reg_899);
return 0;
}
static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
{
- u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909);
+ u16 reg_908 = 0, reg_909 = 0;
u16 reg;
+ if (state->version != SOC7090) {
+ reg_908 = dib7000p_read_word(state, 908);
+ reg_909 = dib7000p_read_word(state, 909);
+ }
+
switch (no) {
case DIBX000_SLOW_ADC_ON:
if (state->version == SOC7090) {
@@ -342,8 +353,10 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad
reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
- dib7000p_write_word(state, 908, reg_908);
- dib7000p_write_word(state, 909, reg_909);
+ if (state->version != SOC7090) {
+ dib7000p_write_word(state, 908, reg_908);
+ dib7000p_write_word(state, 909, reg_909);
+ }
}
static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
@@ -398,6 +411,24 @@ int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
}
EXPORT_SYMBOL(dib7000p_set_wbd_ref);
+int dib7000p_get_agc_values(struct dvb_frontend *fe,
+ u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
+{
+ struct dib7000p_state *state = fe->demodulator_priv;
+
+ if (agc_global != NULL)
+ *agc_global = dib7000p_read_word(state, 394);
+ if (agc1 != NULL)
+ *agc1 = dib7000p_read_word(state, 392);
+ if (agc2 != NULL)
+ *agc2 = dib7000p_read_word(state, 393);
+ if (wbd != NULL)
+ *wbd = dib7000p_read_word(state, 397);
+
+ return 0;
+}
+EXPORT_SYMBOL(dib7000p_get_agc_values);
+
static void dib7000p_reset_pll(struct dib7000p_state *state)
{
struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
@@ -519,7 +550,7 @@ static u16 dib7000p_defaults[] = {
// auto search configuration
3, 2,
0x0004,
- 0x1000,
+ (1<<3)|(1<<11)|(1<<12)|(1<<13),
0x0814, /* Equal Lock */
12, 6,
@@ -595,13 +626,6 @@ static u16 dib7000p_defaults[] = {
1, 235,
0x0062,
- 2, 901,
- 0x0006,
- (3 << 10) | (1 << 6),
-
- 1, 905,
- 0x2c8e,
-
0,
};
@@ -618,15 +642,18 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
dib7000p_write_word(state, 770, 0xffff);
dib7000p_write_word(state, 771, 0xffff);
dib7000p_write_word(state, 772, 0x001f);
- dib7000p_write_word(state, 898, 0x0003);
dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
dib7000p_write_word(state, 770, 0);
dib7000p_write_word(state, 771, 0);
dib7000p_write_word(state, 772, 0);
- dib7000p_write_word(state, 898, 0);
dib7000p_write_word(state, 1280, 0);
+ if (state->version != SOC7090) {
+ dib7000p_write_word(state, 898, 0x0003);
+ dib7000p_write_word(state, 898, 0);
+ }
+
/* default */
dib7000p_reset_pll(state);
@@ -640,7 +667,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
- dib7000p_write_word(state, 273, (1<<6) | 30);
+ dib7000p_write_word(state, 273, (0<<6) | 30);
}
if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
dprintk("OUTPUT_MODE could not be reset.");
@@ -655,7 +682,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
dib7000p_set_bandwidth(state, 8000);
if (state->version == SOC7090) {
- dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
+ dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
} else {
if (state->cfg.tuner_is_baseband)
dib7000p_write_word(state, 36, 0x0755);
@@ -664,6 +691,11 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
}
dib7000p_write_tab(state, dib7000p_defaults);
+ if (state->version != SOC7090) {
+ dib7000p_write_word(state, 901, 0x0006);
+ dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
+ dib7000p_write_word(state, 905, 0x2c8e);
+ }
dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
@@ -780,8 +812,9 @@ static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
}
}
-static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000p_agc_startup(struct dvb_frontend *demod)
{
+ struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
struct dib7000p_state *state = demod->demodulator_priv;
int ret = -1;
u8 *agc_state = &state->agc_state;
@@ -904,15 +937,16 @@ u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
}
EXPORT_SYMBOL(dib7000p_ctrl_timf);
-static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
+static void dib7000p_set_channel(struct dib7000p_state *state,
+ struct dtv_frontend_properties *ch, u8 seq)
{
u16 value, est[4];
- dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
/* nfft, guard, qam, alpha */
value = 0;
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_2K:
value |= (0 << 7);
break;
@@ -924,7 +958,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
value |= (1 << 7);
break;
}
- switch (ch->u.ofdm.guard_interval) {
+ switch (ch->guard_interval) {
case GUARD_INTERVAL_1_32:
value |= (0 << 5);
break;
@@ -939,7 +973,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
value |= (2 << 5);
break;
}
- switch (ch->u.ofdm.constellation) {
+ switch (ch->modulation) {
case QPSK:
value |= (0 << 3);
break;
@@ -970,11 +1004,11 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
value = 0;
if (1 != 0)
value |= (1 << 6);
- if (ch->u.ofdm.hierarchy_information == 1)
+ if (ch->hierarchy == 1)
value |= (1 << 4);
if (1 == 1)
value |= 1;
- switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
case FEC_2_3:
value |= (2 << 1);
break;
@@ -1001,7 +1035,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
dib7000p_write_word(state, 33, 0x0005);
/* P_dvsy_sync_wait */
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_8K:
value = 256;
break;
@@ -1013,7 +1047,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
value = 64;
break;
}
- switch (ch->u.ofdm.guard_interval) {
+ switch (ch->guard_interval) {
case GUARD_INTERVAL_1_16:
value *= 2;
break;
@@ -1034,11 +1068,11 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
/* deactive the possibility of diversity reception if extended interleaver */
- state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
+ state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
dib7000p_set_diversity_in(&state->demod, state->div_state);
/* channel estimation fine configuration */
- switch (ch->u.ofdm.constellation) {
+ switch (ch->modulation) {
case QAM_64:
est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
@@ -1062,27 +1096,31 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
dib7000p_write_word(state, 187 + value, est[value]);
}
-static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000p_autosearch_start(struct dvb_frontend *demod)
{
+ struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
struct dib7000p_state *state = demod->demodulator_priv;
- struct dvb_frontend_parameters schan;
+ struct dtv_frontend_properties schan;
u32 value, factor;
u32 internal = dib7000p_get_internal_freq(state);
schan = *ch;
- schan.u.ofdm.constellation = QAM_64;
- schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
- schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
- schan.u.ofdm.code_rate_HP = FEC_2_3;
- schan.u.ofdm.code_rate_LP = FEC_3_4;
- schan.u.ofdm.hierarchy_information = 0;
+ schan.modulation = QAM_64;
+ schan.guard_interval = GUARD_INTERVAL_1_32;
+ schan.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.code_rate_HP = FEC_2_3;
+ schan.code_rate_LP = FEC_3_4;
+ schan.hierarchy = 0;
dib7000p_set_channel(state, &schan, 7);
- factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
- if (factor >= 5000)
- factor = 1;
- else
+ factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
+ if (factor >= 5000) {
+ if (state->version == SOC7090)
+ factor = 2;
+ else
+ factor = 1;
+ } else
factor = 6;
value = 30 * internal * factor;
@@ -1205,8 +1243,9 @@ static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32
dib7000p_write_word(state, 143, 0);
}
-static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000p_tune(struct dvb_frontend *demod)
{
+ struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
struct dib7000p_state *state = demod->demodulator_priv;
u16 tmp = 0;
@@ -1239,7 +1278,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
tmp = (6 << 8) | 0x80;
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_2K:
tmp |= (2 << 12);
break;
@@ -1255,7 +1294,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
tmp = (0 << 4);
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_2K:
tmp |= 0x6;
break;
@@ -1271,7 +1310,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
tmp = (0 << 4);
- switch (ch->u.ofdm.transmission_mode) {
+ switch (ch->transmission_mode) {
case TRANSMISSION_MODE_2K:
tmp |= 0x6;
break;
@@ -1303,9 +1342,9 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
}
if (state->cfg.spur_protect)
- dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+ dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
- dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
return 0;
}
@@ -1323,7 +1362,7 @@ static int dib7000p_sleep(struct dvb_frontend *demod)
{
struct dib7000p_state *state = demod->demodulator_priv;
if (state->version == SOC7090)
- return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+ return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
}
@@ -1345,93 +1384,94 @@ static int dib7000p_identify(struct dib7000p_state *st)
return 0;
}
-static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib7000p_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dib7000p_state *state = fe->demodulator_priv;
u16 tps = dib7000p_read_word(state, 463);
fep->inversion = INVERSION_AUTO;
- fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
+ fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
switch ((tps >> 8) & 0x3) {
case 0:
- fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+ fep->transmission_mode = TRANSMISSION_MODE_2K;
break;
case 1:
- fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ fep->transmission_mode = TRANSMISSION_MODE_8K;
break;
- /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
+ /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
}
switch (tps & 0x3) {
case 0:
- fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ fep->guard_interval = GUARD_INTERVAL_1_32;
break;
case 1:
- fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+ fep->guard_interval = GUARD_INTERVAL_1_16;
break;
case 2:
- fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+ fep->guard_interval = GUARD_INTERVAL_1_8;
break;
case 3:
- fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+ fep->guard_interval = GUARD_INTERVAL_1_4;
break;
}
switch ((tps >> 14) & 0x3) {
case 0:
- fep->u.ofdm.constellation = QPSK;
+ fep->modulation = QPSK;
break;
case 1:
- fep->u.ofdm.constellation = QAM_16;
+ fep->modulation = QAM_16;
break;
case 2:
default:
- fep->u.ofdm.constellation = QAM_64;
+ fep->modulation = QAM_64;
break;
}
/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
- fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ fep->hierarchy = HIERARCHY_NONE;
switch ((tps >> 5) & 0x7) {
case 1:
- fep->u.ofdm.code_rate_HP = FEC_1_2;
+ fep->code_rate_HP = FEC_1_2;
break;
case 2:
- fep->u.ofdm.code_rate_HP = FEC_2_3;
+ fep->code_rate_HP = FEC_2_3;
break;
case 3:
- fep->u.ofdm.code_rate_HP = FEC_3_4;
+ fep->code_rate_HP = FEC_3_4;
break;
case 5:
- fep->u.ofdm.code_rate_HP = FEC_5_6;
+ fep->code_rate_HP = FEC_5_6;
break;
case 7:
default:
- fep->u.ofdm.code_rate_HP = FEC_7_8;
+ fep->code_rate_HP = FEC_7_8;
break;
}
switch ((tps >> 2) & 0x7) {
case 1:
- fep->u.ofdm.code_rate_LP = FEC_1_2;
+ fep->code_rate_LP = FEC_1_2;
break;
case 2:
- fep->u.ofdm.code_rate_LP = FEC_2_3;
+ fep->code_rate_LP = FEC_2_3;
break;
case 3:
- fep->u.ofdm.code_rate_LP = FEC_3_4;
+ fep->code_rate_LP = FEC_3_4;
break;
case 5:
- fep->u.ofdm.code_rate_LP = FEC_5_6;
+ fep->code_rate_LP = FEC_5_6;
break;
case 7:
default:
- fep->u.ofdm.code_rate_LP = FEC_7_8;
+ fep->code_rate_LP = FEC_7_8;
break;
}
@@ -1440,36 +1480,36 @@ static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa
return 0;
}
-static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib7000p_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct dib7000p_state *state = fe->demodulator_priv;
int time, ret;
- if (state->version == SOC7090) {
+ if (state->version == SOC7090)
dib7090_set_diversity_in(fe, 0);
- dib7090_set_output_mode(fe, OUTMODE_HIGH_Z);
- } else
+ else
dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
/* maybe the parameter has been changed */
state->sfn_workaround_active = buggy_sfn_workaround;
if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, fep);
+ fe->ops.tuner_ops.set_params(fe);
/* start up the AGC */
state->agc_state = 0;
do {
- time = dib7000p_agc_startup(fe, fep);
+ time = dib7000p_agc_startup(fe);
if (time != -1)
msleep(time);
} while (time != -1);
- if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
- fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) {
+ if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
+ fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
int i = 800, found;
- dib7000p_autosearch_start(fe, fep);
+ dib7000p_autosearch_start(fe);
do {
msleep(1);
found = dib7000p_autosearch_is_irq(fe);
@@ -1479,15 +1519,19 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa
if (found == 0 || found == 1)
return 0;
- dib7000p_get_frontend(fe, fep);
+ dib7000p_get_frontend(fe);
}
- ret = dib7000p_tune(fe, fep);
+ ret = dib7000p_tune(fe);
/* make this a config parameter */
- if (state->version == SOC7090)
+ if (state->version == SOC7090) {
dib7090_set_output_mode(fe, state->cfg.output_mode);
- else
+ if (state->cfg.enMpegOutput == 0) {
+ dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
+ dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+ }
+ } else
dib7000p_set_output_mode(state, state->cfg.output_mode);
return ret;
@@ -1831,7 +1875,8 @@ static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg m
return num;
}
-int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address)
+static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msg[], int num, u16 apb_address)
{
struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
u16 word;
@@ -1933,10 +1978,10 @@ static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[]
apb_address = 915;
break;
case 0x27:
- apb_address = 916;
+ apb_address = 917;
break;
case 0x28:
- apb_address = 917;
+ apb_address = 916;
break;
case 0x1d:
i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
@@ -2031,12 +2076,7 @@ static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32
static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
{
- u8 index_buf;
- u16 rx_copy_buf[22];
-
dprintk("Configure DibStream Tx");
- for (index_buf = 0; index_buf < 22; index_buf++)
- rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf);
dib7000p_write_word(state, 1615, 1);
dib7000p_write_word(state, 1603, P_Kin);
@@ -2048,9 +2088,6 @@ static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout
dib7000p_write_word(state, 1612, syncSize);
dib7000p_write_word(state, 1615, 0);
- for (index_buf = 0; index_buf < 22; index_buf++)
- dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]);
-
return 0;
}
@@ -2077,109 +2114,121 @@ static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout
return 0;
}
-static int dib7090_enDivOnHostBus(struct dib7000p_state *state)
-{
- u16 reg;
-
- dprintk("Enable Diversity on host bus");
- reg = (1 << 8) | (1 << 5);
- dib7000p_write_word(state, 1288, reg);
-
- return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
-}
-
-static int dib7090_enAdcOnHostBus(struct dib7000p_state *state)
-{
- u16 reg;
-
- dprintk("Enable ADC on host bus");
- reg = (1 << 7) | (1 << 5);
- dib7000p_write_word(state, 1288, reg);
-
- return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
-}
-
-static int dib7090_enMpegOnHostBus(struct dib7000p_state *state)
+static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
{
- u16 reg;
-
- dprintk("Enable Mpeg on host bus");
- reg = (1 << 9) | (1 << 5);
- dib7000p_write_word(state, 1288, reg);
+ u16 reg_1287 = dib7000p_read_word(state, 1287);
- return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
-}
+ switch (onoff) {
+ case 1:
+ reg_1287 &= ~(1<<7);
+ break;
+ case 0:
+ reg_1287 |= (1<<7);
+ break;
+ }
-static int dib7090_enMpegInput(struct dib7000p_state *state)
-{
- dprintk("Enable Mpeg input");
- return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
+ dib7000p_write_word(state, 1287, reg_1287);
}
-static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
+static void dib7090_configMpegMux(struct dib7000p_state *state,
+ u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
{
- u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1);
-
dprintk("Enable Mpeg mux");
- dib7000p_write_word(state, 1287, reg);
- reg &= ~(1 << 7);
- dib7000p_write_word(state, 1287, reg);
+ dib7090_enMpegMux(state, 0);
- reg = (1 << 4);
- dib7000p_write_word(state, 1288, reg);
+ /* If the input mode is MPEG do not divide the serial clock */
+ if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
+ enSerialClkDiv2 = 0;
- return 0;
+ dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
+ | ((enSerialMode & 0x1) << 1)
+ | (enSerialClkDiv2 & 0x1));
+
+ dib7090_enMpegMux(state, 1);
}
-static int dib7090_disableMpegMux(struct dib7000p_state *state)
+static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
{
- u16 reg;
-
- dprintk("Disable Mpeg mux");
- dib7000p_write_word(state, 1288, 0);
-
- reg = dib7000p_read_word(state, 1287);
- reg &= ~(1 << 7);
- dib7000p_write_word(state, 1287, reg);
+ u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
- return 0;
+ switch (mode) {
+ case MPEG_ON_DIBTX:
+ dprintk("SET MPEG ON DIBSTREAM TX");
+ dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
+ reg_1288 |= (1<<9);
+ break;
+ case DIV_ON_DIBTX:
+ dprintk("SET DIV_OUT ON DIBSTREAM TX");
+ dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
+ reg_1288 |= (1<<8);
+ break;
+ case ADC_ON_DIBTX:
+ dprintk("SET ADC_OUT ON DIBSTREAM TX");
+ dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
+ reg_1288 |= (1<<7);
+ break;
+ default:
+ break;
+ }
+ dib7000p_write_word(state, 1288, reg_1288);
}
-static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode)
+static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
{
- struct dib7000p_state *state = fe->demodulator_priv;
+ u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
switch (mode) {
- case INPUT_MODE_DIVERSITY:
- dprintk("Enable diversity INPUT");
- dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
+ case DEMOUT_ON_HOSTBUS:
+ dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
+ dib7090_enMpegMux(state, 0);
+ reg_1288 |= (1<<6);
+ break;
+ case DIBTX_ON_HOSTBUS:
+ dprintk("SET DIBSTREAM TX ON HOST BUS");
+ dib7090_enMpegMux(state, 0);
+ reg_1288 |= (1<<5);
break;
- case INPUT_MODE_MPEG:
- dprintk("Enable Mpeg INPUT");
- dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
+ case MPEG_ON_HOSTBUS:
+ dprintk("SET MPEG MUX ON HOST BUS");
+ reg_1288 |= (1<<4);
break;
- case INPUT_MODE_OFF:
default:
- dprintk("Disable INPUT");
- dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0);
break;
}
- return 0;
+ dib7000p_write_word(state, 1288, reg_1288);
}
-static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
+int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
{
+ struct dib7000p_state *state = fe->demodulator_priv;
+ u16 reg_1287;
+
switch (onoff) {
- case 0: /* only use the internal way - not the diversity input */
- dib7090_set_input_mode(fe, INPUT_MODE_MPEG);
- break;
- case 1: /* both ways */
- case 2: /* only the diversity input */
- dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY);
- break;
+ case 0: /* only use the internal way - not the diversity input */
+ dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
+ dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
+
+ /* Do not divide the serial clock of MPEG MUX */
+ /* in SERIAL MODE in case input mode MPEG is used */
+ reg_1287 = dib7000p_read_word(state, 1287);
+ /* enSerialClkDiv2 == 1 ? */
+ if ((reg_1287 & 0x1) == 1) {
+ /* force enSerialClkDiv2 = 0 */
+ reg_1287 &= ~0x1;
+ dib7000p_write_word(state, 1287, reg_1287);
+ }
+ state->input_mode_mpeg = 1;
+ break;
+ case 1: /* both ways */
+ case 2: /* only the diversity input */
+ dprintk("%s ON : Enable diversity INPUT", __func__);
+ dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
+ state->input_mode_mpeg = 0;
+ break;
}
+ dib7000p_set_diversity_in(&state->demod, onoff);
return 0;
}
@@ -2204,69 +2253,63 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
case OUTMODE_MPEG2_SERIAL:
if (prefer_mpeg_mux_use) {
- dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux");
- dib7090_enMpegOnHostBus(state);
- dib7090_enMpegInput(state);
- if (state->cfg.enMpegOutput == 1)
- dib7090_enMpegMux(state, 3, 1, 1);
-
- } else { /* Use Smooth block */
- dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc");
- dib7090_disableMpegMux(state);
- dib7000p_write_word(state, 1288, (1 << 6));
- outreg |= (2 << 6) | (0 << 1);
+ dprintk("setting output mode TS_SERIAL using Mpeg Mux");
+ dib7090_configMpegMux(state, 3, 1, 1);
+ dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
+ } else {/* Use Smooth block */
+ dprintk("setting output mode TS_SERIAL using Smooth bloc");
+ dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+ outreg |= (2<<6) | (0 << 1);
}
break;
case OUTMODE_MPEG2_PAR_GATED_CLK:
if (prefer_mpeg_mux_use) {
- dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
- dib7090_enMpegOnHostBus(state);
- dib7090_enMpegInput(state);
- if (state->cfg.enMpegOutput == 1)
- dib7090_enMpegMux(state, 2, 0, 0);
- } else { /* Use Smooth block */
- dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block");
- dib7090_disableMpegMux(state);
- dib7000p_write_word(state, 1288, (1 << 6));
- outreg |= (0 << 6);
+ dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
+ dib7090_configMpegMux(state, 2, 0, 0);
+ dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
+ } else { /* Use Smooth block */
+ dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
+ dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+ outreg |= (0<<6);
}
break;
case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
- dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block");
- dib7090_disableMpegMux(state);
- dib7000p_write_word(state, 1288, (1 << 6));
- outreg |= (1 << 6);
+ dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
+ dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+ outreg |= (1<<6);
break;
case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
- dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block");
- dib7090_disableMpegMux(state);
- dib7000p_write_word(state, 1288, (1 << 6));
- outreg |= (5 << 6);
+ dprintk("setting output mode TS_FIFO using Smooth block");
+ dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+ outreg |= (5<<6);
smo_mode |= (3 << 1);
fifo_threshold = 512;
break;
case OUTMODE_DIVERSITY:
- dprintk("Sip 7090P setting output mode MODE_DIVERSITY");
- dib7090_disableMpegMux(state);
- dib7090_enDivOnHostBus(state);
+ dprintk("setting output mode MODE_DIVERSITY");
+ dib7090_setDibTxMux(state, DIV_ON_DIBTX);
+ dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
break;
case OUTMODE_ANALOG_ADC:
- dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC");
- dib7090_enAdcOnHostBus(state);
+ dprintk("setting output mode MODE_ANALOG_ADC");
+ dib7090_setDibTxMux(state, ADC_ON_DIBTX);
+ dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
break;
}
+ if (mode != OUTMODE_HIGH_Z)
+ outreg |= (1 << 10);
if (state->cfg.output_mpeg2_in_188_bytes)
smo_mode |= (1 << 5);
ret |= dib7000p_write_word(state, 235, smo_mode);
ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
- ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */
+ ret |= dib7000p_write_word(state, 1286, outreg);
return ret;
}
@@ -2296,13 +2339,6 @@ int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
}
EXPORT_SYMBOL(dib7090_tuner_sleep);
-int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
-{
- dprintk("AGC restart callback: %d", restart);
- return 0;
-}
-EXPORT_SYMBOL(dib7090_agc_restart);
-
int dib7090_get_adc_power(struct dvb_frontend *fe)
{
return dib7000p_get_adc_power(fe);
@@ -2391,9 +2427,9 @@ error:
EXPORT_SYMBOL(dib7000p_attach);
static struct dvb_frontend_ops dib7000p_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "DiBcom 7000PC",
- .type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
index 0179f9474bac..b61b03a6e1ed 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -56,11 +56,12 @@ extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw);
extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf);
-extern int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart);
extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff);
extern int dib7090_get_adc_power(struct dvb_frontend *fe);
extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe);
extern int dib7090_slave_reset(struct dvb_frontend *fe);
+extern int dib7000p_get_agc_values(struct dvb_frontend *fe,
+ u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd);
#else
static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
{
@@ -122,12 +123,6 @@ static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
return 0;
}
-static inline int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
@@ -151,6 +146,13 @@ static inline int dib7090_slave_reset(struct dvb_frontend *fe)
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -ENODEV;
}
+
+static inline int dib7000p_get_agc_values(struct dvb_frontend *fe,
+ u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
#endif
#endif
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c
index fe284d5292f5..9ca34f495009 100644
--- a/drivers/media/dvb/frontends/dib8000.c
+++ b/drivers/media/dvb/frontends/dib8000.c
@@ -81,11 +81,15 @@ struct dib8000_state {
u8 i2c_write_buffer[4];
u8 i2c_read_buffer[2];
struct mutex i2c_buffer_lock;
+ u8 input_mode_mpeg;
+
+ u16 tuner_enable;
+ struct i2c_adapter dib8096p_tuner_adap;
};
enum dib8000_power_mode {
- DIB8000M_POWER_ALL = 0,
- DIB8000M_POWER_INTERFACE_ONLY,
+ DIB8000_POWER_ALL = 0,
+ DIB8000_POWER_INTERFACE_ONLY,
};
static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
@@ -428,20 +432,31 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow
/* by default everything is going to be powered off */
u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
+ reg_1280;
+
+ if (state->revision != 0x8090)
reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
+ else
+ reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
/* now, depending on the requested mode, we power on */
switch (mode) {
/* power up everything in the demod */
- case DIB8000M_POWER_ALL:
+ case DIB8000_POWER_ALL:
reg_774 = 0x0000;
reg_775 = 0x0000;
reg_776 = 0x0000;
reg_900 &= 0xfffc;
- reg_1280 &= 0x00ff;
+ if (state->revision != 0x8090)
+ reg_1280 &= 0x00ff;
+ else
+ reg_1280 &= 0x707f;
break;
- case DIB8000M_POWER_INTERFACE_ONLY:
- reg_1280 &= 0x00ff;
+ case DIB8000_POWER_INTERFACE_ONLY:
+ if (state->revision != 0x8090)
+ reg_1280 &= 0x00ff;
+ else
+ reg_1280 &= 0xfa7b;
break;
}
@@ -453,19 +468,67 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow
dib8000_write_word(state, 1280, reg_1280);
}
+static int dib8000_init_sdram(struct dib8000_state *state)
+{
+ u16 reg = 0;
+ dprintk("Init sdram");
+
+ reg = dib8000_read_word(state, 274)&0xfff0;
+ /* P_dintlv_delay_ram = 7 because of MobileSdram */
+ dib8000_write_word(state, 274, reg | 0x7);
+
+ dib8000_write_word(state, 1803, (7<<2));
+
+ reg = dib8000_read_word(state, 1280);
+ /* force restart P_restart_sdram */
+ dib8000_write_word(state, 1280, reg | (1<<2));
+
+ /* release restart P_restart_sdram */
+ dib8000_write_word(state, 1280, reg);
+
+ return 0;
+}
+
static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
{
int ret = 0;
- u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908);
+ u16 reg, reg_907 = dib8000_read_word(state, 907);
+ u16 reg_908 = dib8000_read_word(state, 908);
switch (no) {
case DIBX000_SLOW_ADC_ON:
- reg_908 |= (1 << 1) | (1 << 0);
- ret |= dib8000_write_word(state, 908, reg_908);
- reg_908 &= ~(1 << 1);
+ if (state->revision != 0x8090) {
+ reg_908 |= (1 << 1) | (1 << 0);
+ ret |= dib8000_write_word(state, 908, reg_908);
+ reg_908 &= ~(1 << 1);
+ } else {
+ reg = dib8000_read_word(state, 1925);
+ /* en_slowAdc = 1 & reset_sladc = 1 */
+ dib8000_write_word(state, 1925, reg |
+ (1<<4) | (1<<2));
+
+ /* read acces to make it works... strange ... */
+ reg = dib8000_read_word(state, 1925);
+ msleep(20);
+ /* en_slowAdc = 1 & reset_sladc = 0 */
+ dib8000_write_word(state, 1925, reg & ~(1<<4));
+
+ reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
+ | (0x3 << 12));
+ /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
+ (Vin2 = Vcm) */
+ dib8000_write_word(state, 921, reg | (1 << 14)
+ | (3 << 12));
+ }
break;
case DIBX000_SLOW_ADC_OFF:
+ if (state->revision == 0x8090) {
+ reg = dib8000_read_word(state, 1925);
+ /* reset_sladc = 1 en_slowAdc = 0 */
+ dib8000_write_word(state, 1925,
+ (reg & ~(1<<2)) | (1<<4));
+ }
reg_908 |= (1 << 1) | (1 << 0);
break;
@@ -521,7 +584,12 @@ static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
static int dib8000_sad_calib(struct dib8000_state *state)
{
-/* internal */
+ if (state->revision == 0x8090) {
+ dprintk("%s: the sad calibration is not needed for the dib8096P",
+ __func__);
+ return 0;
+ }
+ /* internal */
dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096
@@ -546,48 +614,129 @@ EXPORT_SYMBOL(dib8000_set_wbd_ref);
static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
{
dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
- dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */
- dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff));
+ if (state->revision != 0x8090) {
+ dib8000_write_word(state, 23,
+ (u16) (((bw->internal * 1000) >> 16) & 0xffff));
+ dib8000_write_word(state, 24,
+ (u16) ((bw->internal * 1000) & 0xffff));
+ } else {
+ dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
+ dib8000_write_word(state, 24,
+ (u16) ((bw->internal / 2 * 1000) & 0xffff));
+ }
dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
- dib8000_write_word(state, 922, bw->sad_cfg);
+ if (state->revision != 0x8090)
+ dib8000_write_word(state, 922, bw->sad_cfg);
}
static void dib8000_reset_pll(struct dib8000_state *state)
{
const struct dibx000_bandwidth_config *pll = state->cfg.pll;
- u16 clk_cfg1;
-
- // clk_cfg0
- dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
-
- // clk_cfg1
- clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
- (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) |
- (pll->pll_range << 1) | (pll->pll_reset << 0);
-
- dib8000_write_word(state, 902, clk_cfg1);
- clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
- dib8000_write_word(state, 902, clk_cfg1);
-
- dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */
-
- /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
- if (state->cfg.pll->ADClkSrc == 0)
- dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) |
- (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
- else if (state->cfg.refclksel != 0)
- dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
- ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) |
- (pll->ADClkSrc << 7) | (0 << 1));
- else
- dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
+ u16 clk_cfg1, reg;
+
+ if (state->revision != 0x8090) {
+ dib8000_write_word(state, 901,
+ (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
+
+ clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
+ (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
+ (1 << 3) | (pll->pll_range << 1) |
+ (pll->pll_reset << 0);
+
+ dib8000_write_word(state, 902, clk_cfg1);
+ clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
+ dib8000_write_word(state, 902, clk_cfg1);
+
+ dprintk("clk_cfg1: 0x%04x", clk_cfg1);
+
+ /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
+ if (state->cfg.pll->ADClkSrc == 0)
+ dib8000_write_word(state, 904,
+ (0 << 15) | (0 << 12) | (0 << 10) |
+ (pll->modulo << 8) |
+ (pll->ADClkSrc << 7) | (0 << 1));
+ else if (state->cfg.refclksel != 0)
+ dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
+ ((state->cfg.refclksel & 0x3) << 10) |
+ (pll->modulo << 8) |
+ (pll->ADClkSrc << 7) | (0 << 1));
+ else
+ dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
+ (3 << 10) | (pll->modulo << 8) |
+ (pll->ADClkSrc << 7) | (0 << 1));
+ } else {
+ dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
+ (pll->pll_range<<12) | (pll->pll_ratio<<6) |
+ (pll->pll_prediv));
+
+ reg = dib8000_read_word(state, 1857);
+ dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
+
+ reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
+ dib8000_write_word(state, 1858, reg | 1);
+
+ dib8000_write_word(state, 904, (pll->modulo << 8));
+ }
dib8000_reset_pll_common(state, pll);
}
+int dib8000_update_pll(struct dvb_frontend *fe,
+ struct dibx000_bandwidth_config *pll)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
+ u8 loopdiv, prediv;
+ u32 internal, xtal;
+
+ /* get back old values */
+ prediv = reg_1856 & 0x3f;
+ loopdiv = (reg_1856 >> 6) & 0x3f;
+
+ if ((pll != NULL) && (pll->pll_prediv != prediv ||
+ pll->pll_ratio != loopdiv)) {
+ dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
+ reg_1856 &= 0xf000;
+ reg_1857 = dib8000_read_word(state, 1857);
+ /* disable PLL */
+ dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
+
+ dib8000_write_word(state, 1856, reg_1856 |
+ ((pll->pll_ratio & 0x3f) << 6) |
+ (pll->pll_prediv & 0x3f));
+
+ /* write new system clk into P_sec_len */
+ internal = dib8000_read32(state, 23) / 1000;
+ dprintk("Old Internal = %d", internal);
+ xtal = 2 * (internal / loopdiv) * prediv;
+ internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
+ dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
+ dprintk("New Internal = %d", internal);
+
+ dib8000_write_word(state, 23,
+ (u16) (((internal / 2) >> 16) & 0xffff));
+ dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
+ /* enable PLL */
+ dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
+
+ while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
+ dprintk("Waiting for PLL to lock");
+
+ /* verify */
+ reg_1856 = dib8000_read_word(state, 1856);
+ dprintk("PLL Updated with prediv = %d and loopdiv = %d",
+ reg_1856&0x3f, (reg_1856>>6)&0x3f);
+
+ return 0;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(dib8000_update_pll);
+
+
static int dib8000_reset_gpio(struct dib8000_state *st)
{
/* reset the GPIOs */
@@ -721,9 +870,6 @@ static const u16 dib8000_defaults[] = {
(3 << 5) | /* P_ctrl_pre_freq_step=3 */
(1 << 0), /* P_pre_freq_win_len=1 */
- 1, 903,
- (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW)
-
0,
};
@@ -740,7 +886,8 @@ static u16 dib8000_identify(struct i2c_device *client)
}
value = dib8000_i2c_read16(client, 897);
- if (value != 0x8000 && value != 0x8001 && value != 0x8002) {
+ if (value != 0x8000 && value != 0x8001 &&
+ value != 0x8002 && value != 0x8090) {
dprintk("wrong Device ID (%x)", value);
return 0;
}
@@ -755,6 +902,9 @@ static u16 dib8000_identify(struct i2c_device *client)
case 0x8002:
dprintk("found DiB8000C");
break;
+ case 0x8090:
+ dprintk("found DiB8096P");
+ break;
}
return value;
}
@@ -763,17 +913,19 @@ static int dib8000_reset(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
- dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */
-
if ((state->revision = dib8000_identify(&state->i2c)) == 0)
return -EINVAL;
+ /* sram lead in, rdy */
+ if (state->revision != 0x8090)
+ dib8000_write_word(state, 1287, 0x0003);
+
if (state->revision == 0x8000)
dprintk("error : dib8000 MA not supported");
dibx000_reset_i2c_master(&state->i2c_master);
- dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
+ dib8000_set_power_mode(state, DIB8000_POWER_ALL);
/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
@@ -782,8 +934,10 @@ static int dib8000_reset(struct dvb_frontend *fe)
dib8000_write_word(state, 770, 0xffff);
dib8000_write_word(state, 771, 0xffff);
dib8000_write_word(state, 772, 0xfffc);
- dib8000_write_word(state, 898, 0x000c); // sad
- dib8000_write_word(state, 1280, 0x004d);
+ if (state->revision == 0x8090)
+ dib8000_write_word(state, 1280, 0x0045);
+ else
+ dib8000_write_word(state, 1280, 0x004d);
dib8000_write_word(state, 1281, 0x000c);
dib8000_write_word(state, 770, 0x0000);
@@ -794,19 +948,25 @@ static int dib8000_reset(struct dvb_frontend *fe)
dib8000_write_word(state, 1281, 0x0000);
/* drives */
- if (state->cfg.drives)
- dib8000_write_word(state, 906, state->cfg.drives);
- else {
- dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
- dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust
+ if (state->revision != 0x8090) {
+ if (state->cfg.drives)
+ dib8000_write_word(state, 906, state->cfg.drives);
+ else {
+ dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
+ /* min drive SDRAM - not optimal - adjust */
+ dib8000_write_word(state, 906, 0x2d98);
+ }
}
dib8000_reset_pll(state);
+ if (state->revision != 0x8090)
+ dib8000_write_word(state, 898, 0x0004);
if (dib8000_reset_gpio(state) != 0)
dprintk("GPIO reset was not successful.");
- if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)
+ if ((state->revision != 0x8090) &&
+ (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
dprintk("OUTPUT_MODE could not be resetted.");
state->current_agc = NULL;
@@ -832,6 +992,8 @@ static int dib8000_reset(struct dvb_frontend *fe)
l = *n++;
}
}
+ if (state->revision != 0x8090)
+ dib8000_write_word(state, 903, (0 << 4) | 2);
state->isdbt_cfg_loaded = 0;
//div_cfg override for special configs
@@ -844,10 +1006,12 @@ static int dib8000_reset(struct dvb_frontend *fe)
dib8000_set_bandwidth(fe, 6000);
dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
- dib8000_sad_calib(state);
- dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+ if (state->revision != 0x8090) {
+ dib8000_sad_calib(state);
+ dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+ }
- dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
+ dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
return 0;
}
@@ -879,6 +1043,8 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
{
struct dibx000_agc_config *agc = NULL;
int i;
+ u16 reg;
+
if (state->current_band == band && state->current_agc != NULL)
return 0;
state->current_band = band;
@@ -914,6 +1080,12 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
dib8000_write_word(state, 106, state->wbd_ref);
else // use default
dib8000_write_word(state, 106, agc->wbd_ref);
+
+ if (state->revision == 0x8090) {
+ reg = dib8000_read_word(state, 922) & (0x3 << 2);
+ dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
+ }
+
dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
dib8000_write_word(state, 108, agc->agc1_max);
dib8000_write_word(state, 109, agc->agc1_min);
@@ -925,7 +1097,10 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
dib8000_write_word(state, 75, agc->agc1_pt3);
- dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */
+ if (state->revision != 0x8090)
+ dib8000_write_word(state, 923,
+ (dib8000_read_word(state, 923) & 0xffe3) |
+ (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
return 0;
}
@@ -968,14 +1143,30 @@ static int dib8000_agc_startup(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
enum frontend_tune_state *tune_state = &state->tune_state;
-
int ret = 0;
+ u16 reg, upd_demod_gain_period = 0x8000;
switch (*tune_state) {
case CT_AGC_START:
// set power-up level: interf+analog+AGC
- dib8000_set_adc_state(state, DIBX000_ADC_ON);
+ if (state->revision != 0x8090)
+ dib8000_set_adc_state(state, DIBX000_ADC_ON);
+ else {
+ dib8000_set_power_mode(state, DIB8000_POWER_ALL);
+
+ reg = dib8000_read_word(state, 1947)&0xff00;
+ dib8000_write_word(state, 1946,
+ upd_demod_gain_period & 0xFFFF);
+ /* bit 14 = enDemodGain */
+ dib8000_write_word(state, 1947, reg | (1<<14) |
+ ((upd_demod_gain_period >> 16) & 0xFF));
+
+ /* enable adc i & q */
+ reg = dib8000_read_word(state, 1920);
+ dib8000_write_word(state, 1920, (reg | 0x3) &
+ (~(1 << 7)));
+ }
if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
*tune_state = CT_AGC_STOP;
@@ -1026,6 +1217,579 @@ static int dib8000_agc_startup(struct dvb_frontend *fe)
}
+static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
+{
+ u16 reg;
+
+ drive &= 0x7;
+
+ /* drive host bus 2, 3, 4 */
+ reg = dib8000_read_word(state, 1798) &
+ ~(0x7 | (0x7 << 6) | (0x7 << 12));
+ reg |= (drive<<12) | (drive<<6) | drive;
+ dib8000_write_word(state, 1798, reg);
+
+ /* drive host bus 5,6 */
+ reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
+ reg |= (drive<<8) | (drive<<2);
+ dib8000_write_word(state, 1799, reg);
+
+ /* drive host bus 7, 8, 9 */
+ reg = dib8000_read_word(state, 1800) &
+ ~(0x7 | (0x7 << 6) | (0x7 << 12));
+ reg |= (drive<<12) | (drive<<6) | drive;
+ dib8000_write_word(state, 1800, reg);
+
+ /* drive host bus 10, 11 */
+ reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
+ reg |= (drive<<8) | (drive<<2);
+ dib8000_write_word(state, 1801, reg);
+
+ /* drive host bus 12, 13, 14 */
+ reg = dib8000_read_word(state, 1802) &
+ ~(0x7 | (0x7 << 6) | (0x7 << 12));
+ reg |= (drive<<12) | (drive<<6) | drive;
+ dib8000_write_word(state, 1802, reg);
+}
+
+static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
+ u32 insertExtSynchro, u32 syncSize)
+{
+ u32 quantif = 3;
+ u32 nom = (insertExtSynchro * P_Kin+syncSize);
+ u32 denom = P_Kout;
+ u32 syncFreq = ((nom << quantif) / denom);
+
+ if ((syncFreq & ((1 << quantif) - 1)) != 0)
+ syncFreq = (syncFreq >> quantif) + 1;
+ else
+ syncFreq = (syncFreq >> quantif);
+
+ if (syncFreq != 0)
+ syncFreq = syncFreq - 1;
+
+ return syncFreq;
+}
+
+static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
+ u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
+ u32 syncWord, u32 syncSize)
+{
+ dprintk("Configure DibStream Tx");
+
+ dib8000_write_word(state, 1615, 1);
+ dib8000_write_word(state, 1603, P_Kin);
+ dib8000_write_word(state, 1605, P_Kout);
+ dib8000_write_word(state, 1606, insertExtSynchro);
+ dib8000_write_word(state, 1608, synchroMode);
+ dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
+ dib8000_write_word(state, 1610, syncWord & 0xffff);
+ dib8000_write_word(state, 1612, syncSize);
+ dib8000_write_word(state, 1615, 0);
+}
+
+static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
+ u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
+ u32 syncWord, u32 syncSize, u32 dataOutRate)
+{
+ u32 syncFreq;
+
+ dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
+
+ if ((P_Kin != 0) && (P_Kout != 0)) {
+ syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
+ insertExtSynchro, syncSize);
+ dib8000_write_word(state, 1542, syncFreq);
+ }
+
+ dib8000_write_word(state, 1554, 1);
+ dib8000_write_word(state, 1536, P_Kin);
+ dib8000_write_word(state, 1537, P_Kout);
+ dib8000_write_word(state, 1539, synchroMode);
+ dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
+ dib8000_write_word(state, 1541, syncWord & 0xffff);
+ dib8000_write_word(state, 1543, syncSize);
+ dib8000_write_word(state, 1544, dataOutRate);
+ dib8000_write_word(state, 1554, 0);
+}
+
+static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
+{
+ u16 reg_1287;
+
+ reg_1287 = dib8000_read_word(state, 1287);
+
+ switch (onoff) {
+ case 1:
+ reg_1287 &= ~(1 << 8);
+ break;
+ case 0:
+ reg_1287 |= (1 << 8);
+ break;
+ }
+
+ dib8000_write_word(state, 1287, reg_1287);
+}
+
+static void dib8096p_configMpegMux(struct dib8000_state *state,
+ u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
+{
+ u16 reg_1287;
+
+ dprintk("Enable Mpeg mux");
+
+ dib8096p_enMpegMux(state, 0);
+
+ /* If the input mode is MPEG do not divide the serial clock */
+ if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
+ enSerialClkDiv2 = 0;
+
+ reg_1287 = ((pulseWidth & 0x1f) << 3) |
+ ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
+ dib8000_write_word(state, 1287, reg_1287);
+
+ dib8096p_enMpegMux(state, 1);
+}
+
+static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
+{
+ u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
+
+ switch (mode) {
+ case MPEG_ON_DIBTX:
+ dprintk("SET MPEG ON DIBSTREAM TX");
+ dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
+ reg_1288 |= (1 << 9); break;
+ case DIV_ON_DIBTX:
+ dprintk("SET DIV_OUT ON DIBSTREAM TX");
+ dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
+ reg_1288 |= (1 << 8); break;
+ case ADC_ON_DIBTX:
+ dprintk("SET ADC_OUT ON DIBSTREAM TX");
+ dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
+ reg_1288 |= (1 << 7); break;
+ default:
+ break;
+ }
+ dib8000_write_word(state, 1288, reg_1288);
+}
+
+static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
+{
+ u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
+
+ switch (mode) {
+ case DEMOUT_ON_HOSTBUS:
+ dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
+ dib8096p_enMpegMux(state, 0);
+ reg_1288 |= (1 << 6);
+ break;
+ case DIBTX_ON_HOSTBUS:
+ dprintk("SET DIBSTREAM TX ON HOST BUS");
+ dib8096p_enMpegMux(state, 0);
+ reg_1288 |= (1 << 5);
+ break;
+ case MPEG_ON_HOSTBUS:
+ dprintk("SET MPEG MUX ON HOST BUS");
+ reg_1288 |= (1 << 4);
+ break;
+ default:
+ break;
+ }
+ dib8000_write_word(state, 1288, reg_1288);
+}
+
+static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ u16 reg_1287;
+
+ switch (onoff) {
+ case 0: /* only use the internal way - not the diversity input */
+ dprintk("%s mode OFF : by default Enable Mpeg INPUT",
+ __func__);
+ /* outputRate = 8 */
+ dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
+
+ /* Do not divide the serial clock of MPEG MUX in
+ SERIAL MODE in case input mode MPEG is used */
+ reg_1287 = dib8000_read_word(state, 1287);
+ /* enSerialClkDiv2 == 1 ? */
+ if ((reg_1287 & 0x1) == 1) {
+ /* force enSerialClkDiv2 = 0 */
+ reg_1287 &= ~0x1;
+ dib8000_write_word(state, 1287, reg_1287);
+ }
+ state->input_mode_mpeg = 1;
+ break;
+ case 1: /* both ways */
+ case 2: /* only the diversity input */
+ dprintk("%s ON : Enable diversity INPUT", __func__);
+ dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
+ state->input_mode_mpeg = 0;
+ break;
+ }
+
+ dib8000_set_diversity_in(state->fe[0], onoff);
+ return 0;
+}
+
+static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ u16 outreg, smo_mode, fifo_threshold;
+ u8 prefer_mpeg_mux_use = 1;
+ int ret = 0;
+
+ dib8096p_host_bus_drive(state, 1);
+
+ fifo_threshold = 1792;
+ smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
+ outreg = dib8000_read_word(state, 1286) &
+ ~((1 << 10) | (0x7 << 6) | (1 << 1));
+
+ switch (mode) {
+ case OUTMODE_HIGH_Z:
+ outreg = 0;
+ break;
+
+ case OUTMODE_MPEG2_SERIAL:
+ if (prefer_mpeg_mux_use) {
+ dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
+ dib8096p_configMpegMux(state, 3, 1, 1);
+ dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
+ } else {/* Use Smooth block */
+ dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
+ dib8096p_setHostBusMux(state,
+ DEMOUT_ON_HOSTBUS);
+ outreg |= (2 << 6) | (0 << 1);
+ }
+ break;
+
+ case OUTMODE_MPEG2_PAR_GATED_CLK:
+ if (prefer_mpeg_mux_use) {
+ dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
+ dib8096p_configMpegMux(state, 2, 0, 0);
+ dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
+ } else { /* Use Smooth block */
+ dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
+ dib8096p_setHostBusMux(state,
+ DEMOUT_ON_HOSTBUS);
+ outreg |= (0 << 6);
+ }
+ break;
+
+ case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
+ dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
+ dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+ outreg |= (1 << 6);
+ break;
+
+ case OUTMODE_MPEG2_FIFO:
+ /* Using Smooth block because not supported
+ by new Mpeg Mux bloc */
+ dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
+ dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+ outreg |= (5 << 6);
+ smo_mode |= (3 << 1);
+ fifo_threshold = 512;
+ break;
+
+ case OUTMODE_DIVERSITY:
+ dprintk("dib8096P setting output mode MODE_DIVERSITY");
+ dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
+ dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+ break;
+
+ case OUTMODE_ANALOG_ADC:
+ dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
+ dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
+ dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+ break;
+ }
+
+ if (mode != OUTMODE_HIGH_Z)
+ outreg |= (1<<10);
+
+ dprintk("output_mpeg2_in_188_bytes = %d",
+ state->cfg.output_mpeg2_in_188_bytes);
+ if (state->cfg.output_mpeg2_in_188_bytes)
+ smo_mode |= (1 << 5);
+
+ ret |= dib8000_write_word(state, 299, smo_mode);
+ /* synchronous fread */
+ ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
+ ret |= dib8000_write_word(state, 1286, outreg);
+
+ return ret;
+}
+
+static int map_addr_to_serpar_number(struct i2c_msg *msg)
+{
+ if (msg->buf[0] <= 15)
+ msg->buf[0] -= 1;
+ else if (msg->buf[0] == 17)
+ msg->buf[0] = 15;
+ else if (msg->buf[0] == 16)
+ msg->buf[0] = 17;
+ else if (msg->buf[0] == 19)
+ msg->buf[0] = 16;
+ else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
+ msg->buf[0] -= 3;
+ else if (msg->buf[0] == 28)
+ msg->buf[0] = 23;
+ else if (msg->buf[0] == 99)
+ msg->buf[0] = 99;
+ else
+ return -EINVAL;
+ return 0;
+}
+
+static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msg[], int num)
+{
+ struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+ u8 n_overflow = 1;
+ u16 i = 1000;
+ u16 serpar_num = msg[0].buf[0];
+
+ while (n_overflow == 1 && i) {
+ n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
+ i--;
+ if (i == 0)
+ dprintk("Tuner ITF: write busy (overflow)");
+ }
+ dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
+ dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
+
+ return num;
+}
+
+static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msg[], int num)
+{
+ struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+ u8 n_overflow = 1, n_empty = 1;
+ u16 i = 1000;
+ u16 serpar_num = msg[0].buf[0];
+ u16 read_word;
+
+ while (n_overflow == 1 && i) {
+ n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
+ i--;
+ if (i == 0)
+ dprintk("TunerITF: read busy (overflow)");
+ }
+ dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
+
+ i = 1000;
+ while (n_empty == 1 && i) {
+ n_empty = dib8000_read_word(state, 1984)&0x1;
+ i--;
+ if (i == 0)
+ dprintk("TunerITF: read busy (empty)");
+ }
+
+ read_word = dib8000_read_word(state, 1987);
+ msg[1].buf[0] = (read_word >> 8) & 0xff;
+ msg[1].buf[1] = (read_word) & 0xff;
+
+ return num;
+}
+
+static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msg[], int num)
+{
+ if (map_addr_to_serpar_number(&msg[0]) == 0) {
+ if (num == 1) /* write */
+ return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
+ else /* read */
+ return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
+ }
+ return num;
+}
+
+static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msg[], int num, u16 apb_address)
+{
+ struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+ u16 word;
+
+ if (num == 1) { /* write */
+ dib8000_write_word(state, apb_address,
+ ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
+ } else {
+ word = dib8000_read_word(state, apb_address);
+ msg[1].buf[0] = (word >> 8) & 0xff;
+ msg[1].buf[1] = (word) & 0xff;
+ }
+ return num;
+}
+
+static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msg[], int num)
+{
+ struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+ u16 apb_address = 0, word;
+ int i = 0;
+
+ switch (msg[0].buf[0]) {
+ case 0x12:
+ apb_address = 1920;
+ break;
+ case 0x14:
+ apb_address = 1921;
+ break;
+ case 0x24:
+ apb_address = 1922;
+ break;
+ case 0x1a:
+ apb_address = 1923;
+ break;
+ case 0x22:
+ apb_address = 1924;
+ break;
+ case 0x33:
+ apb_address = 1926;
+ break;
+ case 0x34:
+ apb_address = 1927;
+ break;
+ case 0x35:
+ apb_address = 1928;
+ break;
+ case 0x36:
+ apb_address = 1929;
+ break;
+ case 0x37:
+ apb_address = 1930;
+ break;
+ case 0x38:
+ apb_address = 1931;
+ break;
+ case 0x39:
+ apb_address = 1932;
+ break;
+ case 0x2a:
+ apb_address = 1935;
+ break;
+ case 0x2b:
+ apb_address = 1936;
+ break;
+ case 0x2c:
+ apb_address = 1937;
+ break;
+ case 0x2d:
+ apb_address = 1938;
+ break;
+ case 0x2e:
+ apb_address = 1939;
+ break;
+ case 0x2f:
+ apb_address = 1940;
+ break;
+ case 0x30:
+ apb_address = 1941;
+ break;
+ case 0x31:
+ apb_address = 1942;
+ break;
+ case 0x32:
+ apb_address = 1943;
+ break;
+ case 0x3e:
+ apb_address = 1944;
+ break;
+ case 0x3f:
+ apb_address = 1945;
+ break;
+ case 0x40:
+ apb_address = 1948;
+ break;
+ case 0x25:
+ apb_address = 936;
+ break;
+ case 0x26:
+ apb_address = 937;
+ break;
+ case 0x27:
+ apb_address = 938;
+ break;
+ case 0x28:
+ apb_address = 939;
+ break;
+ case 0x1d:
+ /* get sad sel request */
+ i = ((dib8000_read_word(state, 921) >> 12)&0x3);
+ word = dib8000_read_word(state, 924+i);
+ msg[1].buf[0] = (word >> 8) & 0xff;
+ msg[1].buf[1] = (word) & 0xff;
+ return num;
+ case 0x1f:
+ if (num == 1) { /* write */
+ word = (u16) ((msg[0].buf[1] << 8) |
+ msg[0].buf[2]);
+ /* in the VGAMODE Sel are located on bit 0/1 */
+ word &= 0x3;
+ word = (dib8000_read_word(state, 921) &
+ ~(3<<12)) | (word<<12);
+ /* Set the proper input */
+ dib8000_write_word(state, 921, word);
+ return num;
+ }
+ }
+
+ if (apb_address != 0) /* R/W acces via APB */
+ return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
+ else /* R/W access via SERPAR */
+ return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
+
+ return 0;
+}
+
+static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
+ .master_xfer = dib8096p_tuner_xfer,
+ .functionality = dib8096p_i2c_func,
+};
+
+struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
+{
+ struct dib8000_state *st = fe->demodulator_priv;
+ return &st->dib8096p_tuner_adap;
+}
+EXPORT_SYMBOL(dib8096p_get_i2c_tuner);
+
+int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ u16 en_cur_state;
+
+ dprintk("sleep dib8096p: %d", onoff);
+
+ en_cur_state = dib8000_read_word(state, 1922);
+
+ /* LNAs and MIX are ON and therefore it is a valid configuration */
+ if (en_cur_state > 0xff)
+ state->tuner_enable = en_cur_state ;
+
+ if (onoff)
+ en_cur_state &= 0x00ff;
+ else {
+ if (state->tuner_enable != 0)
+ en_cur_state = state->tuner_enable;
+ }
+
+ dib8000_write_word(state, 1922, en_cur_state);
+
+ return 0;
+}
+EXPORT_SYMBOL(dib8096p_tuner_sleep);
+
static const s32 lut_1000ln_mant[] =
{
908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
@@ -1051,6 +1815,26 @@ s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
}
EXPORT_SYMBOL(dib8000_get_adc_power);
+int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ int val = 0;
+
+ switch (IQ) {
+ case 1:
+ val = dib8000_read_word(state, 403);
+ break;
+ case 0:
+ val = dib8000_read_word(state, 404);
+ break;
+ }
+ if (val & 0x200)
+ val -= 1024;
+
+ return val;
+}
+EXPORT_SYMBOL(dib8090p_get_dc_power);
+
static void dib8000_update_timf(struct dib8000_state *state)
{
u32 timf = state->timf = dib8000_read32(state, 435);
@@ -1060,6 +1844,26 @@ static void dib8000_update_timf(struct dib8000_state *state)
dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
}
+u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+
+ switch (op) {
+ case DEMOD_TIMF_SET:
+ state->timf = timf;
+ break;
+ case DEMOD_TIMF_UPDATE:
+ dib8000_update_timf(state);
+ break;
+ case DEMOD_TIMF_GET:
+ break;
+ }
+ dib8000_set_bandwidth(state->fe[0], 6000);
+
+ return state->timf;
+}
+EXPORT_SYMBOL(dib8000_ctrl_timf);
+
static const u16 adc_target_16dB[11] = {
(1 << 13) - 825 - 117,
(1 << 13) - 837 - 117,
@@ -1086,6 +1890,9 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
u16 init_prbs = 0xfff;
u16 ana_gain = 0;
+ if (state->revision == 0x8090)
+ dib8000_init_sdram(state);
+
if (state->ber_monitored_layer != LAYER_ALL)
dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
else
@@ -1418,7 +2225,10 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
state->differential_constellation = (seg_diff_mask != 0);
- dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
+ if (state->revision != 0x8090)
+ dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
+ else
+ dib8096p_set_diversity_in(state->fe[0], state->diversity_onoff);
if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
@@ -1870,7 +2680,7 @@ static int dib8000_tune(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
int ret = 0;
- u16 value, mode = fft_to_mode(state);
+ u16 lock, value, mode = fft_to_mode(state);
// we are already tuned - just resuming from suspend
if (state == NULL)
@@ -1924,7 +2734,11 @@ static int dib8000_tune(struct dvb_frontend *fe)
}
// we achieved a coff_cpil_lock - it's time to update the timf
- if ((dib8000_read_word(state, 568) >> 11) & 0x1)
+ if (state->revision != 0x8090)
+ lock = dib8000_read_word(state, 568);
+ else
+ lock = dib8000_read_word(state, 570);
+ if ((lock >> 11) & 0x1)
dib8000_update_timf(state);
//now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start
@@ -1946,11 +2760,14 @@ static int dib8000_wakeup(struct dvb_frontend *fe)
u8 index_frontend;
int ret;
- dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
+ dib8000_set_power_mode(state, DIB8000_POWER_ALL);
dib8000_set_adc_state(state, DIBX000_ADC_ON);
if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
dprintk("could not start Slow ADC");
+ if (state->revision != 0x8090)
+ dib8000_sad_calib(state);
+
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
if (ret < 0)
@@ -1972,8 +2789,9 @@ static int dib8000_sleep(struct dvb_frontend *fe)
return ret;
}
- dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
- dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
+ if (state->revision != 0x8090)
+ dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
+ dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
}
@@ -1992,7 +2810,7 @@ int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tun
}
EXPORT_SYMBOL(dib8000_set_tune_state);
-static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib8000_get_frontend(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
u16 i, val = 0;
@@ -2006,7 +2824,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
if (stat&FE_HAS_SYNC) {
dprintk("TMCC lock on the slave%i", index_frontend);
/* synchronize the cache with the other frontends */
- state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);
+ state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
if (sub_index_frontend != index_frontend) {
state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
@@ -2028,7 +2846,10 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
- val = dib8000_read_word(state, 570);
+ if (state->revision == 0x8090)
+ val = dib8000_read_word(state, 572);
+ else
+ val = dib8000_read_word(state, 570);
fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
switch ((val & 0x30) >> 4) {
case 1:
@@ -2135,7 +2956,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
return 0;
}
-static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib8000_set_frontend(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
u8 nbr_pending, exit_condition, index_frontend;
@@ -2158,9 +2979,14 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
- dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
+ if (state->revision != 0x8090)
+ dib8000_set_output_mode(state->fe[index_frontend],
+ OUTMODE_HIGH_Z);
+ else
+ dib8096p_set_output_mode(state->fe[index_frontend],
+ OUTMODE_HIGH_Z);
if (state->fe[index_frontend]->ops.tuner_ops.set_params)
- state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep);
+ state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
}
@@ -2215,7 +3041,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {
- int i = 80000;
+ int i = 100;
u8 found = 0;
u8 tune_failed = 0;
@@ -2243,6 +3069,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
default:
dprintk("unhandled autosearch result");
case 1:
+ tune_failed |= (1 << index_frontend);
dprintk("autosearch failed for the frontend%i", index_frontend);
break;
}
@@ -2261,21 +3088,44 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
dprintk("tune success on frontend%i", index_frontend_success);
- dib8000_get_frontend(fe, fep);
+ dib8000_get_frontend(fe);
}
for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
ret = dib8000_tune(state->fe[index_frontend]);
/* set output mode and diversity input */
- dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
- for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
- dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
- dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
- }
+ if (state->revision != 0x8090) {
+ dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
+ for (index_frontend = 1;
+ (index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
+ (state->fe[index_frontend] != NULL);
+ index_frontend++) {
+ dib8000_set_output_mode(state->fe[index_frontend],
+ OUTMODE_DIVERSITY);
+ dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
+ }
- /* turn off the diversity of the last chip */
- dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
+ /* turn off the diversity of the last chip */
+ dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
+ } else {
+ dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
+ if (state->cfg.enMpegOutput == 0) {
+ dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
+ dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+ }
+ for (index_frontend = 1;
+ (index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
+ (state->fe[index_frontend] != NULL);
+ index_frontend++) {
+ dib8096p_set_output_mode(state->fe[index_frontend],
+ OUTMODE_DIVERSITY);
+ dib8096p_set_diversity_in(state->fe[index_frontend-1], 1);
+ }
+
+ /* turn off the diversity of the last chip */
+ dib8096p_set_diversity_in(state->fe[index_frontend-1], 0);
+ }
return ret;
}
@@ -2284,15 +3134,22 @@ static u16 dib8000_read_lock(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
+ if (state->revision == 0x8090)
+ return dib8000_read_word(state, 570);
return dib8000_read_word(state, 568);
}
static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
{
struct dib8000_state *state = fe->demodulator_priv;
- u16 lock_slave = 0, lock = dib8000_read_word(state, 568);
+ u16 lock_slave = 0, lock;
u8 index_frontend;
+ if (state->revision == 0x8090)
+ lock = dib8000_read_word(state, 570);
+ else
+ lock = dib8000_read_word(state, 568);
+
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
@@ -2330,14 +3187,26 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
{
struct dib8000_state *state = fe->demodulator_priv;
- *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments
+
+ /* 13 segments */
+ if (state->revision == 0x8090)
+ *ber = (dib8000_read_word(state, 562) << 16) |
+ dib8000_read_word(state, 563);
+ else
+ *ber = (dib8000_read_word(state, 560) << 16) |
+ dib8000_read_word(state, 561);
return 0;
}
static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
{
struct dib8000_state *state = fe->demodulator_priv;
- *unc = dib8000_read_word(state, 565); // packet error on 13 seg
+
+ /* packet error on 13 seg */
+ if (state->revision == 0x8090)
+ *unc = dib8000_read_word(state, 567);
+ else
+ *unc = dib8000_read_word(state, 565);
return 0;
}
@@ -2370,14 +3239,20 @@ static u32 dib8000_get_snr(struct dvb_frontend *fe)
u32 n, s, exp;
u16 val;
- val = dib8000_read_word(state, 542);
+ if (state->revision != 0x8090)
+ val = dib8000_read_word(state, 542);
+ else
+ val = dib8000_read_word(state, 544);
n = (val >> 6) & 0xff;
exp = (val & 0x3f);
if ((exp & 0x20) != 0)
exp -= 0x40;
n <<= exp+16;
- val = dib8000_read_word(state, 543);
+ if (state->revision != 0x8090)
+ val = dib8000_read_word(state, 543);
+ else
+ val = dib8000_read_word(state, 545);
s = (val >> 6) & 0xff;
exp = (val & 0x3f);
if ((exp & 0x20) != 0)
@@ -2401,7 +3276,7 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
snr_master += dib8000_get_snr(state->fe[index_frontend]);
- if (snr_master != 0) {
+ if ((snr_master >> 16) != 0) {
snr_master = 10*intlog10(snr_master>>16);
*snr = snr_master / ((1 << 24) / 10);
}
@@ -2458,7 +3333,8 @@ struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int sla
EXPORT_SYMBOL(dib8000_get_slave_frontend);
-int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
+int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
+ u8 default_addr, u8 first_addr, u8 is_dib8096p)
{
int k = 0, ret = 0;
u8 new_addr = 0;
@@ -2488,9 +3364,12 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
new_addr = first_addr + (k << 1);
client.addr = new_addr;
- dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
- if (dib8000_identify(&client) == 0) {
+ if (!is_dib8096p)
dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
+ if (dib8000_identify(&client) == 0) {
+ /* sram lead in, rdy */
+ if (!is_dib8096p)
+ dib8000_i2c_write16(&client, 1287, 0x0003);
client.addr = default_addr;
if (dib8000_identify(&client) == 0) {
dprintk("#%d: not identified", k);
@@ -2549,6 +3428,7 @@ static void dib8000_release(struct dvb_frontend *fe)
dvb_frontend_detach(st->fe[index_frontend]);
dibx000_exit_i2c_master(&st->i2c_master);
+ i2c_del_adapter(&st->dib8096p_tuner_adap);
kfree(st->fe[0]);
kfree(st);
}
@@ -2581,9 +3461,9 @@ int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
EXPORT_SYMBOL(dib8000_pid_filter);
static const struct dvb_frontend_ops dib8000_ops = {
+ .delsys = { SYS_ISDBT },
.info = {
.name = "DiBcom 8000 ISDB-T",
- .type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 62500,
@@ -2651,6 +3531,15 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
+ /* init 8096p tuner adapter */
+ strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
+ sizeof(state->dib8096p_tuner_adap.name));
+ state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
+ state->dib8096p_tuner_adap.algo_data = NULL;
+ state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
+ i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
+ i2c_add_adapter(&state->dib8096p_tuner_adap);
+
dib8000_reset(fe);
dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h
index 617f9eba3a09..39591bb172c1 100644
--- a/drivers/media/dvb/frontends/dib8000.h
+++ b/drivers/media/dvb/frontends/dib8000.h
@@ -32,6 +32,7 @@ struct dib8000_config {
u8 div_cfg;
u8 output_mode;
u8 refclksel;
+ u8 enMpegOutput:1;
};
#define DEFAULT_DIB8000_I2C_ADDRESS 18
@@ -40,7 +41,8 @@ struct dib8000_config {
extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
-extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr);
+extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
+ u8 default_addr, u8 first_addr, u8 is_dib8096p);
extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value);
@@ -50,6 +52,13 @@ extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_st
extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe);
extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe);
extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode);
+extern struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe);
+extern int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff);
+extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ);
+extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
+ uint8_t op, uint32_t timf);
+extern int dib8000_update_pll(struct dvb_frontend *fe,
+ struct dibx000_bandwidth_config *pll);
extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe);
extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
@@ -66,7 +75,9 @@ static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe
return NULL;
}
-static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
+static inline int dib8000_i2c_enumeration(struct i2c_adapter *host,
+ int no_of_demods, u8 default_addr, u8 first_addr,
+ u8 is_dib8096p)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -ENODEV;
@@ -109,11 +120,38 @@ static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
}
+static inline struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+static inline int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return 0;
+}
static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return 0;
}
+static inline int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return 0;
+}
+static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
+ uint8_t op, uint32_t timf)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return 0;
+}
+static inline int dib8000_update_pll(struct dvb_frontend *fe,
+ struct dibx000_bandwidth_config *pll)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c
index 660f80661ed4..80848b4c15d4 100644
--- a/drivers/media/dvb/frontends/dib9000.c
+++ b/drivers/media/dvb/frontends/dib9000.c
@@ -33,7 +33,7 @@ struct i2c_device {
/* lock */
#define DIB_LOCK struct mutex
-#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock) < 0) dprintk("could not get the lock"); } while (0)
+#define DibAcquireLock(lock) mutex_lock_interruptible(lock)
#define DibReleaseLock(lock) mutex_unlock(lock)
#define DibInitLock(lock) mutex_init(lock)
#define DibFreeLock(lock)
@@ -446,7 +446,10 @@ static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u1
if (!state->platform.risc.fw_is_running)
return -EIO;
- DibAcquireLock(&state->platform.risc.mem_lock);
+ if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
dib9000_risc_mem_setup(state, cmd | 0x80);
dib9000_risc_mem_read_chunks(state, b, len);
DibReleaseLock(&state->platform.risc.mem_lock);
@@ -459,7 +462,10 @@ static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8
if (!state->platform.risc.fw_is_running)
return -EIO;
- DibAcquireLock(&state->platform.risc.mem_lock);
+ if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
dib9000_risc_mem_setup(state, cmd);
dib9000_risc_mem_write_chunks(state, b, m->size);
DibReleaseLock(&state->platform.risc.mem_lock);
@@ -531,7 +537,10 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data,
if (!state->platform.risc.fw_is_running)
return -EINVAL;
- DibAcquireLock(&state->platform.risc.mbx_if_lock);
+ if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
tmp = MAX_MAILBOX_TRY;
do {
size = dib9000_read_word_attr(state, 1043, attr) & 0xff;
@@ -593,7 +602,10 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id,
if (!state->platform.risc.fw_is_running)
return 0;
- DibAcquireLock(&state->platform.risc.mbx_if_lock);
+ if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) {
+ dprintk("could not get the lock");
+ return 0;
+ }
if (risc_id == 1)
mc_base = 16;
else
@@ -701,7 +713,10 @@ static int dib9000_mbx_process(struct dib9000_state *state, u16 attr)
if (!state->platform.risc.fw_is_running)
return -1;
- DibAcquireLock(&state->platform.risc.mbx_lock);
+ if (DibAcquireLock(&state->platform.risc.mbx_lock) < 0) {
+ dprintk("could not get the lock");
+ return -1;
+ }
if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */
ret = dib9000_mbx_fetch_to_cache(state, attr);
@@ -1136,7 +1151,7 @@ static int dib9000_fw_init(struct dib9000_state *state)
return 0;
}
-static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_frontend_parameters *ch)
+static void dib9000_fw_set_channel_head(struct dib9000_state *state)
{
u8 b[9];
u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000;
@@ -1157,7 +1172,7 @@ static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_
dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b);
}
-static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel)
+static int dib9000_fw_get_channel(struct dvb_frontend *fe)
{
struct dib9000_state *state = fe->demodulator_priv;
struct dibDVBTChannel {
@@ -1178,7 +1193,10 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
struct dibDVBTChannel *ch;
int ret = 0;
- DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
ret = -EIO;
goto error;
@@ -1309,7 +1327,7 @@ error:
return ret;
}
-static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel)
+static int dib9000_fw_set_channel_union(struct dvb_frontend *fe)
{
struct dib9000_state *state = fe->demodulator_priv;
struct dibDVBTChannel {
@@ -1454,7 +1472,7 @@ static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_fron
return 0;
}
-static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+static int dib9000_fw_tune(struct dvb_frontend *fe)
{
struct dib9000_state *state = fe->demodulator_priv;
int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN;
@@ -1462,7 +1480,7 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete
switch (state->tune_state) {
case CT_DEMOD_START:
- dib9000_fw_set_channel_head(state, ch);
+ dib9000_fw_set_channel_head(state);
/* write the channel context - a channel is initialized to 0, so it is OK */
dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info);
@@ -1471,7 +1489,7 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete
if (search)
dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0);
else {
- dib9000_fw_set_channel_union(fe, ch);
+ dib9000_fw_set_channel_union(fe);
dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0);
}
state->tune_state = CT_DEMOD_STEP_1;
@@ -1660,7 +1678,10 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2
p[12] = 0;
}
- DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ dprintk("could not get the lock");
+ return 0;
+ }
dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p);
@@ -1768,7 +1789,10 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
return 0;
}
- DibAcquireLock(&state->demod_lock);
+ if (DibAcquireLock(&state->demod_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
val = dib9000_read_word(state, 294 + 1) & 0xffef;
val |= (onoff & 0x1) << 4;
@@ -1800,7 +1824,10 @@ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
return 0;
}
- DibAcquireLock(&state->demod_lock);
+ if (DibAcquireLock(&state->demod_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
ret = dib9000_write_word(state, 300 + 1 + id,
onoff ? (1 << 13) | pid : 0);
@@ -1848,7 +1875,10 @@ static int dib9000_sleep(struct dvb_frontend *fe)
u8 index_frontend;
int ret = 0;
- DibAcquireLock(&state->demod_lock);
+ if (DibAcquireLock(&state->demod_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
if (ret < 0)
@@ -1867,15 +1897,19 @@ static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_fron
return 0;
}
-static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib9000_get_frontend(struct dvb_frontend *fe)
{
struct dib9000_state *state = fe->demodulator_priv;
u8 index_frontend, sub_index_frontend;
fe_status_t stat;
int ret = 0;
- if (state->get_frontend_internal == 0)
- DibAcquireLock(&state->demod_lock);
+ if (state->get_frontend_internal == 0) {
+ if (DibAcquireLock(&state->demod_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
+ }
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
@@ -1883,7 +1917,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
dprintk("TPS lock on the slave%i", index_frontend);
/* synchronize the cache with the other frontends */
- state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);
+ state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL);
sub_index_frontend++) {
if (sub_index_frontend != index_frontend) {
@@ -1911,7 +1945,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
}
/* get the channel from master chip */
- ret = dib9000_fw_get_channel(fe, fep);
+ ret = dib9000_fw_get_channel(fe);
if (ret != 0)
goto return_value;
@@ -1958,7 +1992,7 @@ static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_fronte
return 0;
}
-static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib9000_set_frontend(struct dvb_frontend *fe)
{
struct dib9000_state *state = fe->demodulator_priv;
int sleep_time, sleep_time_slave;
@@ -1978,13 +2012,18 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
}
state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
- DibAcquireLock(&state->demod_lock);
+ if (DibAcquireLock(&state->demod_lock) < 0) {
+ dprintk("could not get the lock");
+ return 0;
+ }
fe->dtv_property_cache.delivery_system = SYS_DVBT;
/* set the master status */
- if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
- fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) {
+ if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO ||
+ state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO ||
+ state->fe[0]->dtv_property_cache.modulation == QAM_AUTO ||
+ state->fe[0]->dtv_property_cache.code_rate_HP == FEC_AUTO) {
/* no channel specified, autosearch the channel */
state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN;
} else
@@ -2008,9 +2047,9 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
index_frontend_success = 0;
do {
- sleep_time = dib9000_fw_tune(state->fe[0], NULL);
+ sleep_time = dib9000_fw_tune(state->fe[0]);
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
- sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL);
+ sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
if (sleep_time == FE_CALLBACK_TIME_NEVER)
sleep_time = sleep_time_slave;
else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
@@ -2052,7 +2091,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
/* synchronize all the channel cache */
state->get_frontend_internal = 1;
- dib9000_get_frontend(state->fe[0], fep);
+ dib9000_get_frontend(state->fe[0]);
state->get_frontend_internal = 0;
/* retune the other frontends with the found channel */
@@ -2068,7 +2107,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
sleep_time = FE_CALLBACK_TIME_NEVER;
for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
if (index_frontend != index_frontend_success) {
- sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL);
+ sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
if (sleep_time == FE_CALLBACK_TIME_NEVER)
sleep_time = sleep_time_slave;
else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
@@ -2136,7 +2175,10 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
u8 index_frontend;
u16 lock = 0, lock_slave = 0;
- DibAcquireLock(&state->demod_lock);
+ if (DibAcquireLock(&state->demod_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
@@ -2166,8 +2208,15 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
u16 *c;
int ret = 0;
- DibAcquireLock(&state->demod_lock);
- DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+ if (DibAcquireLock(&state->demod_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ dprintk("could not get the lock");
+ ret = -EINTR;
+ goto error;
+ }
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
DibReleaseLock(&state->platform.risc.mem_mbx_lock);
ret = -EIO;
@@ -2194,7 +2243,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
u16 val;
int ret = 0;
- DibAcquireLock(&state->demod_lock);
+ if (DibAcquireLock(&state->demod_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
*strength = 0;
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
@@ -2204,8 +2256,13 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
*strength += val;
}
- DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ dprintk("could not get the lock");
+ ret = -EINTR;
+ goto error;
+ }
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+ DibReleaseLock(&state->platform.risc.mem_mbx_lock);
ret = -EIO;
goto error;
}
@@ -2230,9 +2287,14 @@ static u32 dib9000_get_snr(struct dvb_frontend *fe)
u32 n, s, exp;
u16 val;
- DibAcquireLock(&state->platform.risc.mem_mbx_lock);
- if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
- return -EIO;
+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ dprintk("could not get the lock");
+ return 0;
+ }
+ if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+ DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ return 0;
+ }
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
DibReleaseLock(&state->platform.risc.mem_mbx_lock);
@@ -2264,7 +2326,10 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
u8 index_frontend;
u32 snr_master;
- DibAcquireLock(&state->demod_lock);
+ if (DibAcquireLock(&state->demod_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
snr_master = dib9000_get_snr(fe);
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
snr_master += dib9000_get_snr(state->fe[index_frontend]);
@@ -2286,9 +2351,17 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
u16 *c = (u16 *)state->i2c_read_buffer;
int ret = 0;
- DibAcquireLock(&state->demod_lock);
- DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+ if (DibAcquireLock(&state->demod_lock) < 0) {
+ dprintk("could not get the lock");
+ return -EINTR;
+ }
+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ dprintk("could not get the lock");
+ ret = -EINTR;
+ goto error;
+ }
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+ DibReleaseLock(&state->platform.risc.mem_mbx_lock);
ret = -EIO;
goto error;
}
@@ -2495,9 +2568,9 @@ error:
EXPORT_SYMBOL(dib9000_attach);
static struct dvb_frontend_ops dib9000_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "DiBcom 9000",
- .type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
index 5e011474be43..5f484881d7b1 100644
--- a/drivers/media/dvb/frontends/dibx000_common.h
+++ b/drivers/media/dvb/frontends/dibx000_common.h
@@ -146,14 +146,8 @@ enum dibx000_adc_states {
DIBX000_VBG_DISABLE,
};
-#define BANDWIDTH_TO_KHZ(v) ((v) == BANDWIDTH_8_MHZ ? 8000 : \
- (v) == BANDWIDTH_7_MHZ ? 7000 : \
- (v) == BANDWIDTH_6_MHZ ? 6000 : 8000)
-
-#define BANDWIDTH_TO_INDEX(v) ( \
- (v) == 8000 ? BANDWIDTH_8_MHZ : \
- (v) == 7000 ? BANDWIDTH_7_MHZ : \
- (v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ )
+#define BANDWIDTH_TO_KHZ(v) ((v) / 1000)
+#define BANDWIDTH_TO_HZ(v) ((v) * 1000)
/* Chip output mode. */
#define OUTMODE_HIGH_Z 0
@@ -276,4 +270,11 @@ struct dibSubbandSelection {
#define DEMOD_TIMF_GET 0x01
#define DEMOD_TIMF_UPDATE 0x02
+#define MPEG_ON_DIBTX 1
+#define DIV_ON_DIBTX 2
+#define ADC_ON_DIBTX 3
+#define DEMOUT_ON_HOSTBUS 4
+#define DIBTX_ON_HOSTBUS 5
+#define MPEG_ON_HOSTBUS 6
+
#endif
diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb/frontends/drxd.h
index 7113535844f2..34398738f9bc 100644
--- a/drivers/media/dvb/frontends/drxd.h
+++ b/drivers/media/dvb/frontends/drxd.h
@@ -48,8 +48,6 @@ struct drxd_config {
u8 disable_i2c_gate_ctrl;
u32 IF;
- int (*pll_set) (void *priv, void *priv_params,
- u8 pll_addr, u8 demoda_addr, s32 *off);
s16(*osc_deviation) (void *priv, s16 dev, int flag);
};
diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c
index 88e46f4cdbb2..f380eb43e9d5 100644
--- a/drivers/media/dvb/frontends/drxd_hard.c
+++ b/drivers/media/dvb/frontends/drxd_hard.c
@@ -101,9 +101,9 @@ struct SCfgAgc {
struct SNoiseCal {
int cpOpt;
- u16 cpNexpOfs;
- u16 tdCal2k;
- u16 tdCal8k;
+ short cpNexpOfs;
+ short tdCal2k;
+ short tdCal8k;
};
enum app_env {
@@ -120,7 +120,7 @@ enum EIFFilter {
struct drxd_state {
struct dvb_frontend frontend;
struct dvb_frontend_ops ops;
- struct dvb_frontend_parameters param;
+ struct dtv_frontend_properties props;
const struct firmware *fw;
struct device *dev;
@@ -914,14 +914,13 @@ static int load_firmware(struct drxd_state *state, const char *fw_name)
return -EIO;
}
- state->microcode = kmalloc(fw->size, GFP_KERNEL);
+ state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (state->microcode == NULL) {
release_firmware(fw);
printk(KERN_ERR "drxd: firmware load failure: no memory\n");
return -ENOMEM;
}
- memcpy(state->microcode, fw->data, fw->size);
state->microcode_length = fw->size;
release_firmware(fw);
return 0;
@@ -1622,14 +1621,14 @@ static int CorrectSysClockDeviation(struct drxd_state *state)
break;
}
- switch (state->param.u.ofdm.bandwidth) {
- case BANDWIDTH_8_MHZ:
+ switch (state->props.bandwidth_hz) {
+ case 8000000:
bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
break;
- case BANDWIDTH_6_MHZ:
+ case 6000000:
bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
break;
default:
@@ -1804,7 +1803,7 @@ static int StartDiversity(struct drxd_state *state)
status = WriteTable(state, state->m_StartDiversityEnd);
if (status < 0)
break;
- if (state->param.u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
+ if (state->props.bandwidth_hz == 8000000) {
status = WriteTable(state, state->m_DiversityDelay8MHZ);
if (status < 0)
break;
@@ -1906,7 +1905,7 @@ static int SetCfgNoiseCalibration(struct drxd_state *state,
static int DRX_Start(struct drxd_state *state, s32 off)
{
- struct dvb_ofdm_parameters *p = &state->param.u.ofdm;
+ struct dtv_frontend_properties *p = &state->props;
int status;
u16 transmissionParams = 0;
@@ -1971,7 +1970,7 @@ static int DRX_Start(struct drxd_state *state, s32 off)
if (status < 0)
break;
- mirrorFreqSpect = (state->param.inversion == INVERSION_ON);
+ mirrorFreqSpect = (state->props.inversion == INVERSION_ON);
switch (p->transmission_mode) {
default: /* Not set, detect it automatically */
@@ -2021,7 +2020,7 @@ static int DRX_Start(struct drxd_state *state, s32 off)
break;
}
- switch (p->hierarchy_information) {
+ switch (p->hierarchy) {
case HIERARCHY_1:
transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A1;
if (state->type_A) {
@@ -2147,7 +2146,7 @@ static int DRX_Start(struct drxd_state *state, s32 off)
if (status < 0)
break;
- switch (p->constellation) {
+ switch (p->modulation) {
default:
operationMode |= SC_RA_RAM_OP_AUTO_CONST__M;
/* fall through , try first guess
@@ -2331,9 +2330,11 @@ static int DRX_Start(struct drxd_state *state, s32 off)
by SC for fix for some 8K,1/8 guard but is restored by
InitEC and ResetEC
functions */
- switch (p->bandwidth) {
- case BANDWIDTH_AUTO:
- case BANDWIDTH_8_MHZ:
+ switch (p->bandwidth_hz) {
+ case 0:
+ p->bandwidth_hz = 8000000;
+ /* fall through */
+ case 8000000:
/* (64/7)*(8/8)*1000000 */
bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
@@ -2341,14 +2342,14 @@ static int DRX_Start(struct drxd_state *state, s32 off)
status = Write16(state,
FE_AG_REG_IND_DEL__A, 50, 0x0000);
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
/* (64/7)*(7/8)*1000000 */
bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
bandwidthParam = 0x4807; /*binary:0100 1000 0000 0111 */
status = Write16(state,
FE_AG_REG_IND_DEL__A, 59, 0x0000);
break;
- case BANDWIDTH_6_MHZ:
+ case 6000000:
/* (64/7)*(6/8)*1000000 */
bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
bandwidthParam = 0x0F07; /*binary: 0000 1111 0000 0111 */
@@ -2887,41 +2888,26 @@ static int drxd_sleep(struct dvb_frontend *fe)
return 0;
}
-static int drxd_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
-{
- return 0;
-}
-
static int drxd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
return drxd_config_i2c(fe, enable);
}
-static int drxd_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int drxd_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct drxd_state *state = fe->demodulator_priv;
s32 off = 0;
- state->param = *param;
+ state->props = *p;
DRX_Stop(state);
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, param);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
- /* FIXME: move PLL drivers */
- if (state->config.pll_set &&
- state->config.pll_set(state->priv, param,
- state->config.pll_address,
- state->config.demoda_address, &off) < 0) {
- printk(KERN_ERR "Error in pll_set\n");
- return -1;
- }
-
msleep(200);
return DRX_Start(state, off);
@@ -2935,10 +2921,9 @@ static void drxd_release(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops drxd_ops = {
-
+ .delsys = { SYS_DVBT},
.info = {
.name = "Micronas DRXD DVB-T",
- .type = FE_OFDM,
.frequency_min = 47125000,
.frequency_max = 855250000,
.frequency_stepsize = 166667,
@@ -2958,7 +2943,6 @@ static struct dvb_frontend_ops drxd_ops = {
.i2c_gate_ctrl = drxd_i2c_gate_ctrl,
.set_frontend = drxd_set_frontend,
- .get_frontend = drxd_get_frontend,
.get_tune_settings = drxd_get_tune_settings,
.read_status = drxd_read_status,
diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb/frontends/drxk.h
index 58baf419560c..9d64e4fea066 100644
--- a/drivers/media/dvb/frontends/drxk.h
+++ b/drivers/media/dvb/frontends/drxk.h
@@ -7,13 +7,19 @@
/**
* struct drxk_config - Configure the initial parameters for DRX-K
*
- * adr: I2C Address of the DRX-K
- * single_master: Device is on the single master mode
- * no_i2c_bridge: Don't switch the I2C bridge to talk with tuner
- * antenna_gpio: GPIO bit used to control the antenna
- * antenna_dvbt: GPIO bit for changing antenna to DVB-C. A value of 1
+ * @adr: I2C Address of the DRX-K
+ * @parallel_ts: True means that the device uses parallel TS,
+ * Serial otherwise.
+ * @dynamic_clk: True means that the clock will be dynamically
+ * adjusted. Static clock otherwise.
+ * @enable_merr_cfg: Enable SIO_PDR_PERR_CFG/SIO_PDR_MVAL_CFG.
+ * @single_master: Device is on the single master mode
+ * @no_i2c_bridge: Don't switch the I2C bridge to talk with tuner
+ * @antenna_gpio: GPIO bit used to control the antenna
+ * @antenna_dvbt: GPIO bit for changing antenna to DVB-C. A value of 1
* means that 1=DVBC, 0 = DVBT. Zero means the opposite.
- * microcode_name: Name of the firmware file with the microcode
+ * @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength.
+ * @microcode_name: Name of the firmware file with the microcode
*
* On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
* UIO-3.
@@ -22,22 +28,26 @@ struct drxk_config {
u8 adr;
bool single_master;
bool no_i2c_bridge;
+ bool parallel_ts;
+ bool dynamic_clk;
+ bool enable_merr_cfg;
bool antenna_dvbt;
u16 antenna_gpio;
+ u8 mpeg_out_clk_strength;
+ int chunk_size;
+
const char *microcode_name;
};
#if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \
&& defined(MODULE))
extern struct dvb_frontend *drxk_attach(const struct drxk_config *config,
- struct i2c_adapter *i2c,
- struct dvb_frontend **fe_t);
+ struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *drxk_attach(const struct drxk_config *config,
- struct i2c_adapter *i2c,
- struct dvb_frontend **fe_t)
+ struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c
index f6431ef827dc..36d11756492f 100644
--- a/drivers/media/dvb/frontends/drxk_hard.c
+++ b/drivers/media/dvb/frontends/drxk_hard.c
@@ -28,7 +28,6 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
-#include <linux/version.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
@@ -91,10 +90,6 @@ bool IsA1WithRomCode(struct drxk_state *state)
#define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03)
#endif
-#ifndef DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH
-#define DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH (0x06)
-#endif
-
#define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700
#define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500
@@ -368,10 +363,10 @@ static int i2c_read(struct i2c_adapter *adap,
}
if (debug > 2) {
int i;
- dprintk(2, ": read from ");
+ dprintk(2, ": read from");
for (i = 0; i < len; i++)
printk(KERN_CONT " %02x", msg[i]);
- printk(KERN_CONT "Value = ");
+ printk(KERN_CONT ", value = ");
for (i = 0; i < alen; i++)
printk(KERN_CONT " %02x", answ[i]);
printk(KERN_CONT "\n");
@@ -650,9 +645,6 @@ static int init_state(struct drxk_state *state)
u32 ulQual83 = DEFAULT_MER_83;
u32 ulQual93 = DEFAULT_MER_93;
- u32 ulDVBTStaticTSClock = 1;
- u32 ulDVBCStaticTSClock = 1;
-
u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
@@ -660,10 +652,8 @@ static int init_state(struct drxk_state *state)
/* io_pad_cfg_mode output mode is drive always */
/* io_pad_cfg_drive is set to power 2 (23 mA) */
u32 ulGPIOCfg = 0x0113;
- u32 ulSerialMode = 1;
u32 ulInvertTSClock = 0;
u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
- u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH;
u32 ulDVBTBitrate = 50000000;
u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
@@ -681,7 +671,8 @@ static int init_state(struct drxk_state *state)
state->m_hasOOB = false;
state->m_hasAudio = false;
- state->m_ChunkSize = 124;
+ if (!state->m_ChunkSize)
+ state->m_ChunkSize = 124;
state->m_oscClockFreq = 0;
state->m_smartAntInverted = false;
@@ -810,15 +801,12 @@ static int init_state(struct drxk_state *state)
/* MPEG output configuration */
state->m_enableMPEGOutput = true; /* If TRUE; enable MPEG ouput */
state->m_insertRSByte = false; /* If TRUE; insert RS byte */
- state->m_enableParallel = true; /* If TRUE;
- parallel out otherwise serial */
state->m_invertDATA = false; /* If TRUE; invert DATA signals */
state->m_invertERR = false; /* If TRUE; invert ERR signal */
state->m_invertSTR = false; /* If TRUE; invert STR signals */
state->m_invertVAL = false; /* If TRUE; invert VAL signals */
state->m_invertCLK = (ulInvertTSClock != 0); /* If TRUE; invert CLK signals */
- state->m_DVBTStaticCLK = (ulDVBTStaticTSClock != 0);
- state->m_DVBCStaticCLK = (ulDVBCStaticTSClock != 0);
+
/* If TRUE; static MPEG clockrate will be used;
otherwise clockrate will adapt to the bitrate of the TS */
@@ -826,7 +814,6 @@ static int init_state(struct drxk_state *state)
state->m_DVBCBitrate = ulDVBCBitrate;
state->m_TSDataStrength = (ulTSDataStrength & 0x07);
- state->m_TSClockkStrength = (ulTSClockkStrength & 0x07);
/* Maximum bitrate in b/s in case static clockrate is selected */
state->m_mpegTsStaticBitrate = 19392658;
@@ -856,8 +843,6 @@ static int init_state(struct drxk_state *state)
state->m_bPowerDown = false;
state->m_currentPowerMode = DRX_POWER_DOWN;
- state->m_enableParallel = (ulSerialMode == 0);
-
state->m_rfmirror = (ulRfMirror == 0);
state->m_IfAgcPol = false;
return 0;
@@ -946,6 +931,9 @@ static int GetDeviceCapabilities(struct drxk_state *state)
status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo);
if (status < 0)
goto error;
+
+printk(KERN_ERR "drxk: status = 0x%08x\n", sioTopJtagidLo);
+
/* driver 0.9.0 */
switch ((sioTopJtagidLo >> 29) & 0xF) {
case 0:
@@ -963,7 +951,8 @@ static int GetDeviceCapabilities(struct drxk_state *state)
default:
state->m_deviceSpin = DRXK_SPIN_UNKNOWN;
status = -EINVAL;
- printk(KERN_ERR "drxk: Spin unknown\n");
+ printk(KERN_ERR "drxk: Spin %d unknown\n",
+ (sioTopJtagidLo >> 29) & 0xF);
goto error2;
}
switch ((sioTopJtagidLo >> 12) & 0xFF) {
@@ -1189,8 +1178,11 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
int status = -1;
u16 sioPdrMclkCfg = 0;
u16 sioPdrMdxCfg = 0;
+ u16 err_cfg = 0;
- dprintk(1, "\n");
+ dprintk(1, ": mpeg %s, %s mode\n",
+ mpegEnable ? "enable" : "disable",
+ state->m_enableParallel ? "parallel" : "serial");
/* stop lock indicator process */
status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
@@ -1252,12 +1244,17 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg);
if (status < 0)
goto error;
- status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000); /* Disable */
+
+ if (state->enable_merr_cfg)
+ err_cfg = sioPdrMdxCfg;
+
+ status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg);
if (status < 0)
goto error;
- status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000); /* Disable */
+ status = write16(state, SIO_PDR_MVAL_CFG__A, err_cfg);
if (status < 0)
goto error;
+
if (state->m_enableParallel == true) {
/* paralel -> enable MD1 to MD7 */
status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg);
@@ -1846,6 +1843,7 @@ static int SetOperationMode(struct drxk_state *state,
*/
switch (oMode) {
case OM_DVBT:
+ dprintk(1, ": DVB-T\n");
state->m_OperationMode = oMode;
status = SetDVBTStandard(state, oMode);
if (status < 0)
@@ -1853,6 +1851,8 @@ static int SetOperationMode(struct drxk_state *state,
break;
case OM_QAM_ITU_A: /* fallthrough */
case OM_QAM_ITU_C:
+ dprintk(1, ": DVB-C Annex %c\n",
+ (state->m_OperationMode == OM_QAM_ITU_A) ? 'A' : 'C');
state->m_OperationMode = oMode;
status = SetQAMStandard(state, oMode);
if (status < 0)
@@ -1881,7 +1881,7 @@ static int Start(struct drxk_state *state, s32 offsetFreq,
state->m_DrxkState != DRXK_DTV_STARTED)
goto error;
- state->m_bMirrorFreqSpect = (state->param.inversion == INVERSION_ON);
+ state->m_bMirrorFreqSpect = (state->props.inversion == INVERSION_ON);
if (IntermediateFrequency < 0) {
state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect;
@@ -2503,7 +2503,7 @@ static int GetQAMSignalToNoise(struct drxk_state *state,
u16 qamSlErrPower = 0; /* accum. error between
raw and sliced symbols */
u32 qamSlSigPower = 0; /* used for MER, depends of
- QAM constellation */
+ QAM modulation */
u32 qamSlMer = 0; /* QAM MER */
dprintk(1, "\n");
@@ -2517,7 +2517,7 @@ static int GetQAMSignalToNoise(struct drxk_state *state,
return -EINVAL;
}
- switch (state->param.u.qam.modulation) {
+ switch (state->props.modulation) {
case QAM_16:
qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
break;
@@ -2748,7 +2748,7 @@ static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality)
if (status < 0)
break;
- switch (state->param.u.qam.modulation) {
+ switch (state->props.modulation) {
case QAM_16:
SignalToNoiseRel = SignalToNoise - 200;
break;
@@ -3813,7 +3813,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
/*== Write channel settings to device =====================================*/
/* mode */
- switch (state->param.u.ofdm.transmission_mode) {
+ switch (state->props.transmission_mode) {
case TRANSMISSION_MODE_AUTO:
default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
@@ -3827,7 +3827,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
}
/* guard */
- switch (state->param.u.ofdm.guard_interval) {
+ switch (state->props.guard_interval) {
default:
case GUARD_INTERVAL_AUTO:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
@@ -3847,7 +3847,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
}
/* hierarchy */
- switch (state->param.u.ofdm.hierarchy_information) {
+ switch (state->props.hierarchy) {
case HIERARCHY_AUTO:
case HIERARCHY_NONE:
default:
@@ -3867,8 +3867,8 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
}
- /* constellation */
- switch (state->param.u.ofdm.constellation) {
+ /* modulation */
+ switch (state->props.modulation) {
case QAM_AUTO:
default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
@@ -3911,7 +3911,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
#endif
/* coderate */
- switch (state->param.u.ofdm.code_rate_HP) {
+ switch (state->props.code_rate_HP) {
case FEC_AUTO:
default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
@@ -3940,9 +3940,11 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
/* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed
by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC
functions */
- switch (state->param.u.ofdm.bandwidth) {
- case BANDWIDTH_AUTO:
- case BANDWIDTH_8_MHZ:
+ switch (state->props.bandwidth_hz) {
+ case 0:
+ state->props.bandwidth_hz = 8000000;
+ /* fall though */
+ case 8000000:
bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ;
status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052);
if (status < 0)
@@ -3961,7 +3963,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
if (status < 0)
goto error;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ;
status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491);
if (status < 0)
@@ -3980,7 +3982,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
if (status < 0)
goto error;
break;
- case BANDWIDTH_6_MHZ:
+ case 6000000:
bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ;
status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073);
if (status < 0)
@@ -4187,7 +4189,7 @@ error:
/**
* \brief Setup of the QAM Measurement intervals for signal quality
* \param demod instance of demod.
-* \param constellation current constellation.
+* \param modulation current modulation.
* \return DRXStatus_t.
*
* NOTE:
@@ -4196,7 +4198,7 @@ error:
*
*/
static int SetQAMMeasurement(struct drxk_state *state,
- enum EDrxkConstellation constellation,
+ enum EDrxkConstellation modulation,
u32 symbolRate)
{
u32 fecBitsDesired = 0; /* BER accounting period */
@@ -4210,11 +4212,11 @@ static int SetQAMMeasurement(struct drxk_state *state,
fecRsPrescale = 1;
/* fecBitsDesired = symbolRate [kHz] *
FrameLenght [ms] *
- (constellation + 1) *
+ (modulation + 1) *
SyncLoss (== 1) *
ViterbiLoss (==1)
*/
- switch (constellation) {
+ switch (modulation) {
case DRX_CONSTELLATION_QAM16:
fecBitsDesired = 4 * symbolRate;
break;
@@ -5281,12 +5283,12 @@ static int QAMSetSymbolrate(struct drxk_state *state)
/* Select & calculate correct IQM rate */
adcFrequency = (state->m_sysClockFreq * 1000) / 3;
ratesel = 0;
- /* printk(KERN_DEBUG "drxk: SR %d\n", state->param.u.qam.symbol_rate); */
- if (state->param.u.qam.symbol_rate <= 1188750)
+ /* printk(KERN_DEBUG "drxk: SR %d\n", state->props.symbol_rate); */
+ if (state->props.symbol_rate <= 1188750)
ratesel = 3;
- else if (state->param.u.qam.symbol_rate <= 2377500)
+ else if (state->props.symbol_rate <= 2377500)
ratesel = 2;
- else if (state->param.u.qam.symbol_rate <= 4755000)
+ else if (state->props.symbol_rate <= 4755000)
ratesel = 1;
status = write16(state, IQM_FD_RATESEL__A, ratesel);
if (status < 0)
@@ -5295,7 +5297,7 @@ static int QAMSetSymbolrate(struct drxk_state *state)
/*
IqmRcRate = ((Fadc / (symbolrate * (4<<ratesel))) - 1) * (1<<23)
*/
- symbFreq = state->param.u.qam.symbol_rate * (1 << ratesel);
+ symbFreq = state->props.symbol_rate * (1 << ratesel);
if (symbFreq == 0) {
/* Divide by zero */
status = -EINVAL;
@@ -5311,7 +5313,7 @@ static int QAMSetSymbolrate(struct drxk_state *state)
/*
LcSymbFreq = round (.125 * symbolrate / adcFreq * (1<<15))
*/
- symbFreq = state->param.u.qam.symbol_rate;
+ symbFreq = state->props.symbol_rate;
if (adcFrequency == 0) {
/* Divide by zero */
status = -EINVAL;
@@ -5412,7 +5414,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
goto error;
/* Set params */
- switch (state->param.u.qam.modulation) {
+ switch (state->props.modulation) {
case QAM_256:
state->m_Constellation = DRX_CONSTELLATION_QAM256;
break;
@@ -5435,7 +5437,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
}
if (status < 0)
goto error;
- setParamParameters[0] = state->m_Constellation; /* constellation */
+ setParamParameters[0] = state->m_Constellation; /* modulation */
setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */
if (state->m_OperationMode == OM_QAM_ITU_C)
setParamParameters[2] = QAM_TOP_ANNEX_C;
@@ -5457,7 +5459,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
if (status < 0)
goto error;
- setParamParameters[0] = state->m_Constellation; /* constellation */
+ setParamParameters[0] = state->m_Constellation; /* modulation */
setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */
status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 2, setParamParameters, 1, &cmdResult);
}
@@ -5466,7 +5468,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
/*
* STEP 3: enable the system in a mode where the ADC provides valid
- * signal setup constellation independent registers
+ * signal setup modulation independent registers
*/
#if 0
status = SetFrequency(channel, tunerFreqOffset));
@@ -5478,7 +5480,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
goto error;
/* Setup BER measurement */
- status = SetQAMMeasurement(state, state->m_Constellation, state->param.u. qam.symbol_rate);
+ status = SetQAMMeasurement(state, state->m_Constellation, state->props.symbol_rate);
if (status < 0)
goto error;
@@ -5560,8 +5562,8 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
if (status < 0)
goto error;
- /* STEP 4: constellation specific setup */
- switch (state->param.u.qam.modulation) {
+ /* STEP 4: modulation specific setup */
+ switch (state->props.modulation) {
case QAM_16:
status = SetQAM16(state);
break;
@@ -5591,7 +5593,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
goto error;
/* Re-configure MPEG output, requires knowledge of channel bitrate */
- /* extAttr->currentChannel.constellation = channel->constellation; */
+ /* extAttr->currentChannel.modulation = channel->modulation; */
/* extAttr->currentChannel.symbolrate = channel->symbolrate; */
status = MPEGTSDtoSetup(state, state->m_OperationMode);
if (status < 0)
@@ -6063,9 +6065,7 @@ static int init_drxk(struct drxk_state *state)
if (status < 0)
goto error;
- if (!state->microcode_name)
- load_microcode(state, "drxk_a3.mc");
- else
+ if (state->microcode_name)
load_microcode(state, state->microcode_name);
/* disable token-ring bus through OFDM block for possible ucode upload */
@@ -6167,7 +6167,7 @@ error:
return status;
}
-static void drxk_c_release(struct dvb_frontend *fe)
+static void drxk_release(struct dvb_frontend *fe)
{
struct drxk_state *state = fe->demodulator_priv;
@@ -6175,24 +6175,12 @@ static void drxk_c_release(struct dvb_frontend *fe)
kfree(state);
}
-static int drxk_c_init(struct dvb_frontend *fe)
-{
- struct drxk_state *state = fe->demodulator_priv;
-
- dprintk(1, "\n");
- if (mutex_trylock(&state->ctlock) == 0)
- return -EBUSY;
- SetOperationMode(state, OM_QAM_ITU_A);
- return 0;
-}
-
-static int drxk_c_sleep(struct dvb_frontend *fe)
+static int drxk_sleep(struct dvb_frontend *fe)
{
struct drxk_state *state = fe->demodulator_priv;
dprintk(1, "\n");
ShutDown(state);
- mutex_unlock(&state->ctlock);
return 0;
}
@@ -6204,9 +6192,10 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
return ConfigureI2CBridge(state, enable ? true : false);
}
-static int drxk_set_parameters(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int drxk_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ u32 delsys = p->delivery_system, old_delsys;
struct drxk_state *state = fe->demodulator_priv;
u32 IF;
@@ -6218,14 +6207,39 @@ static int drxk_set_parameters(struct dvb_frontend *fe,
return -EINVAL;
}
-
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
- state->param = *p;
+
+ old_delsys = state->props.delivery_system;
+ state->props = *p;
+
+ if (old_delsys != delsys) {
+ ShutDown(state);
+ switch (delsys) {
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
+ if (!state->m_hasDVBC)
+ return -EINVAL;
+ state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ? true : false;
+ if (state->m_itut_annex_c)
+ SetOperationMode(state, OM_QAM_ITU_C);
+ else
+ SetOperationMode(state, OM_QAM_ITU_A);
+ break;
+ case SYS_DVBT:
+ if (!state->m_hasDVBT)
+ return -EINVAL;
+ SetOperationMode(state, OM_DVBT);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
fe->ops.tuner_ops.get_if_frequency(fe, &IF);
Start(state, 0, IF);
@@ -6234,13 +6248,6 @@ static int drxk_set_parameters(struct dvb_frontend *fe,
return 0;
}
-static int drxk_c_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
-{
- dprintk(1, "\n");
- return 0;
-}
-
static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct drxk_state *state = fe->demodulator_priv;
@@ -6300,102 +6307,51 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
return 0;
}
-static int drxk_c_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
+static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
*sets)
{
- dprintk(1, "\n");
- sets->min_delay_ms = 3000;
- sets->max_drift = 0;
- sets->step_size = 0;
- return 0;
-}
-
-static void drxk_t_release(struct dvb_frontend *fe)
-{
- /*
- * There's nothing to release here, as the state struct
- * is already freed by drxk_c_release.
- */
-}
-
-static int drxk_t_init(struct dvb_frontend *fe)
-{
- struct drxk_state *state = fe->demodulator_priv;
-
- dprintk(1, "\n");
- if (mutex_trylock(&state->ctlock) == 0)
- return -EBUSY;
- SetOperationMode(state, OM_DVBT);
- return 0;
-}
-
-static int drxk_t_sleep(struct dvb_frontend *fe)
-{
- struct drxk_state *state = fe->demodulator_priv;
-
- dprintk(1, "\n");
- mutex_unlock(&state->ctlock);
- return 0;
-}
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-static int drxk_t_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
-{
dprintk(1, "\n");
-
- return 0;
+ switch (p->delivery_system) {
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
+ case SYS_DVBT:
+ sets->min_delay_ms = 3000;
+ sets->max_drift = 0;
+ sets->step_size = 0;
+ return 0;
+ default:
+ return -EINVAL;
+ }
}
-static struct dvb_frontend_ops drxk_c_ops = {
- .info = {
- .name = "DRXK DVB-C",
- .type = FE_QAM,
- .frequency_stepsize = 62500,
- .frequency_min = 47000000,
- .frequency_max = 862000000,
- .symbol_rate_min = 870000,
- .symbol_rate_max = 11700000,
- .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
- FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO},
- .release = drxk_c_release,
- .init = drxk_c_init,
- .sleep = drxk_c_sleep,
- .i2c_gate_ctrl = drxk_gate_ctrl,
-
- .set_frontend = drxk_set_parameters,
- .get_frontend = drxk_c_get_frontend,
- .get_tune_settings = drxk_c_get_tune_settings,
-
- .read_status = drxk_read_status,
- .read_ber = drxk_read_ber,
- .read_signal_strength = drxk_read_signal_strength,
- .read_snr = drxk_read_snr,
- .read_ucblocks = drxk_read_ucblocks,
-};
-
-static struct dvb_frontend_ops drxk_t_ops = {
+static struct dvb_frontend_ops drxk_ops = {
+ /* .delsys will be filled dynamically */
.info = {
- .name = "DRXK DVB-T",
- .type = FE_OFDM,
- .frequency_min = 47125000,
- .frequency_max = 865000000,
- .frequency_stepsize = 166667,
- .frequency_tolerance = 0,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
- FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_FEC_AUTO |
- FE_CAN_QAM_16 | FE_CAN_QAM_64 |
- FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS},
- .release = drxk_t_release,
- .init = drxk_t_init,
- .sleep = drxk_t_sleep,
+ .name = "DRXK",
+ .frequency_min = 47000000,
+ .frequency_max = 865000000,
+ /* For DVB-C */
+ .symbol_rate_min = 870000,
+ .symbol_rate_max = 11700000,
+ /* For DVB-T */
+ .frequency_stepsize = 166667,
+
+ .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_MUTE_TS |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER |
+ FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO
+ },
+
+ .release = drxk_release,
+ .sleep = drxk_sleep,
.i2c_gate_ctrl = drxk_gate_ctrl,
.set_frontend = drxk_set_parameters,
- .get_frontend = drxk_t_get_frontend,
+ .get_tune_settings = drxk_get_tune_settings,
.read_status = drxk_read_status,
.read_ber = drxk_read_ber,
@@ -6405,9 +6361,10 @@ static struct dvb_frontend_ops drxk_t_ops = {
};
struct dvb_frontend *drxk_attach(const struct drxk_config *config,
- struct i2c_adapter *i2c,
- struct dvb_frontend **fe_t)
+ struct i2c_adapter *i2c)
{
+ int n;
+
struct drxk_state *state = NULL;
u8 adr = config->adr;
@@ -6423,6 +6380,27 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
state->no_i2c_bridge = config->no_i2c_bridge;
state->antenna_gpio = config->antenna_gpio;
state->antenna_dvbt = config->antenna_dvbt;
+ state->m_ChunkSize = config->chunk_size;
+ state->enable_merr_cfg = config->enable_merr_cfg;
+
+ if (config->dynamic_clk) {
+ state->m_DVBTStaticCLK = 0;
+ state->m_DVBCStaticCLK = 0;
+ } else {
+ state->m_DVBTStaticCLK = 1;
+ state->m_DVBCStaticCLK = 1;
+ }
+
+
+ if (config->mpeg_out_clk_strength)
+ state->m_TSClockkStrength = config->mpeg_out_clk_strength & 0x07;
+ else
+ state->m_TSClockkStrength = 0x06;
+
+ if (config->parallel_ts)
+ state->m_enableParallel = true;
+ else
+ state->m_enableParallel = false;
/* NOTE: as more UIO bits will be used, add them to the mask */
state->UIO_mask = config->antenna_gpio;
@@ -6434,21 +6412,30 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
state->m_GPIO &= ~state->antenna_gpio;
mutex_init(&state->mutex);
- mutex_init(&state->ctlock);
- memcpy(&state->c_frontend.ops, &drxk_c_ops,
- sizeof(struct dvb_frontend_ops));
- memcpy(&state->t_frontend.ops, &drxk_t_ops,
- sizeof(struct dvb_frontend_ops));
- state->c_frontend.demodulator_priv = state;
- state->t_frontend.demodulator_priv = state;
+ memcpy(&state->frontend.ops, &drxk_ops, sizeof(drxk_ops));
+ state->frontend.demodulator_priv = state;
init_state(state);
if (init_drxk(state) < 0)
goto error;
- *fe_t = &state->t_frontend;
- return &state->c_frontend;
+ /* Initialize the supported delivery systems */
+ n = 0;
+ if (state->m_hasDVBC) {
+ state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
+ state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C;
+ strlcat(state->frontend.ops.info.name, " DVB-C",
+ sizeof(state->frontend.ops.info.name));
+ }
+ if (state->m_hasDVBT) {
+ state->frontend.ops.delsys[n++] = SYS_DVBT;
+ strlcat(state->frontend.ops.info.name, " DVB-T",
+ sizeof(state->frontend.ops.info.name));
+ }
+
+ printk(KERN_INFO "drxk: frontend initialized.\n");
+ return &state->frontend;
error:
printk(KERN_ERR "drxk: not found\n");
diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h
index a05c32eecdcc..4bbf841de83a 100644
--- a/drivers/media/dvb/frontends/drxk_hard.h
+++ b/drivers/media/dvb/frontends/drxk_hard.h
@@ -195,9 +195,8 @@ struct DRXKOfdmScCmd_t {
};
struct drxk_state {
- struct dvb_frontend c_frontend;
- struct dvb_frontend t_frontend;
- struct dvb_frontend_parameters param;
+ struct dvb_frontend frontend;
+ struct dtv_frontend_properties props;
struct device *dev;
struct i2c_adapter *i2c;
@@ -205,7 +204,6 @@ struct drxk_state {
void *priv;
struct mutex mutex;
- struct mutex ctlock;
u32 m_Instance; /**< Channel 1,2,3 or 4 */
@@ -263,6 +261,8 @@ struct drxk_state {
u8 m_TSDataStrength;
u8 m_TSClockkStrength;
+ bool m_itut_annex_c; /* If true, uses ITU-T DVB-C Annex C, instead of Annex A */
+
enum DRXMPEGStrWidth_t m_widthSTR; /**< MPEG start width */
u32 m_mpegTsStaticBitrate; /**< Maximum bitrate in b/s in case
static clockrate is selected */
@@ -332,6 +332,7 @@ struct drxk_state {
u16 UIO_mask; /* Bits used by UIO */
+ bool enable_merr_cfg;
bool single_master;
bool no_i2c_bridge;
bool antenna_dvbt;
diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c
index 90bf573308b0..af65d013db11 100644
--- a/drivers/media/dvb/frontends/ds3000.c
+++ b/drivers/media/dvb/frontends/ds3000.c
@@ -934,20 +934,6 @@ error2:
}
EXPORT_SYMBOL(ds3000_attach);
-static int ds3000_set_property(struct dvb_frontend *fe,
- struct dtv_property *tvp)
-{
- dprintk("%s(..)\n", __func__);
- return 0;
-}
-
-static int ds3000_get_property(struct dvb_frontend *fe,
- struct dtv_property *tvp)
-{
- dprintk("%s(..)\n", __func__);
- return 0;
-}
-
static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
s32 carrier_offset_khz)
{
@@ -967,8 +953,7 @@ static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
return 0;
}
-static int ds3000_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int ds3000_set_frontend(struct dvb_frontend *fe)
{
struct ds3000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -994,15 +979,15 @@ static int ds3000_set_frontend(struct dvb_frontend *fe,
div4 = 0;
/* calculate and set freq divider */
- if (p->frequency < 1146000) {
+ if (c->frequency < 1146000) {
ds3000_tuner_writereg(state, 0x10, 0x11);
div4 = 1;
- ndiv = ((p->frequency * (6 + 8) * 4) +
+ ndiv = ((c->frequency * (6 + 8) * 4) +
(DS3000_XTAL_FREQ / 2)) /
DS3000_XTAL_FREQ - 1024;
} else {
ds3000_tuner_writereg(state, 0x10, 0x01);
- ndiv = ((p->frequency * (6 + 8) * 2) +
+ ndiv = ((c->frequency * (6 + 8) * 2) +
(DS3000_XTAL_FREQ / 2)) /
DS3000_XTAL_FREQ - 1024;
}
@@ -1101,7 +1086,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe,
msleep(60);
offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ
- / (6 + 8) / (div4 + 1) / 2 - p->frequency;
+ / (6 + 8) / (div4 + 1) / 2 - c->frequency;
/* ds3000 global reset */
ds3000_writereg(state, 0x07, 0x80);
@@ -1210,7 +1195,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe,
for (i = 0; i < 30 ; i++) {
ds3000_read_status(fe, &status);
- if (status && FE_HAS_LOCK)
+ if (status & FE_HAS_LOCK)
break;
msleep(10);
@@ -1220,13 +1205,13 @@ static int ds3000_set_frontend(struct dvb_frontend *fe,
}
static int ds3000_tune(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p,
+ bool re_tune,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status)
{
- if (p) {
- int ret = ds3000_set_frontend(fe, p);
+ if (re_tune) {
+ int ret = ds3000_set_frontend(fe);
if (ret)
return ret;
}
@@ -1279,10 +1264,9 @@ static int ds3000_sleep(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops ds3000_ops = {
-
+ .delsys = { SYS_DVBS, SYS_DVBS2},
.info = {
.name = "Montage Technology DS3000/TS2020",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1011, /* kHz for QPSK frontends */
@@ -1312,8 +1296,6 @@ static struct dvb_frontend_ops ds3000_ops = {
.diseqc_send_burst = ds3000_diseqc_send_burst,
.get_frontend_algo = ds3000_get_algo,
- .set_property = ds3000_set_property,
- .get_property = ds3000_get_property,
.set_frontend = ds3000_set_frontend,
.tune = ds3000_tune,
};
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 62a65efdf8d6..1ab34838221c 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -61,8 +61,7 @@ struct dvb_pll_desc {
u32 min;
u32 max;
u32 iffreq;
- void (*set)(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params);
+ void (*set)(struct dvb_frontend *fe, u8 *buf);
u8 *initdata;
u8 *initdata2;
u8 *sleepdata;
@@ -93,10 +92,10 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
},
};
-static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
+static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf)
{
- if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth)
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ if (bw == 7000000)
buf[3] |= 0x10;
}
@@ -186,10 +185,10 @@ static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
/* Philips TDA6650/TDA6651
* used in Panasonic ENV77H11D5
*/
-static void tda665x_bw(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
+static void tda665x_bw(struct dvb_frontend *fe, u8 *buf)
{
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ if (bw == 8000000)
buf[3] |= 0x08;
}
@@ -220,10 +219,10 @@ static struct dvb_pll_desc dvb_pll_tda665x = {
/* Infineon TUA6034
* used in LG TDTP E102P
*/
-static void tua6034_bw(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
+static void tua6034_bw(struct dvb_frontend *fe, u8 *buf)
{
- if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth)
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ if (bw == 7000000)
buf[3] |= 0x08;
}
@@ -244,10 +243,10 @@ static struct dvb_pll_desc dvb_pll_tua6034 = {
/* ALPS TDED4
* used in Nebula-Cards and USB boxes
*/
-static void tded4_bw(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
+static void tded4_bw(struct dvb_frontend *fe, u8 *buf)
{
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ if (bw == 8000000)
buf[3] |= 0x04;
}
@@ -319,11 +318,11 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
},
};
-static void opera1_bw(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
+static void opera1_bw(struct dvb_frontend *fe, u8 *buf)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_pll_priv *priv = fe->tuner_priv;
- u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000;
+ u32 b_w = (c->symbol_rate * 27) / 32000;
struct i2c_msg msg = {
.addr = priv->pll_i2c_address,
.flags = 0,
@@ -392,8 +391,7 @@ static struct dvb_pll_desc dvb_pll_opera1 = {
}
};
-static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
+static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf)
{
struct dvb_pll_priv *priv = fe->tuner_priv;
struct i2c_msg msg = {
@@ -537,30 +535,29 @@ static struct dvb_pll_desc *pll_list[] = {
/* code */
static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
+ const u32 frequency)
{
struct dvb_pll_priv *priv = fe->tuner_priv;
struct dvb_pll_desc *desc = priv->pll_desc;
u32 div;
int i;
- if (params->frequency != 0 && (params->frequency < desc->min ||
- params->frequency > desc->max))
+ if (frequency && (frequency < desc->min || frequency > desc->max))
return -EINVAL;
for (i = 0; i < desc->count; i++) {
- if (params->frequency > desc->entries[i].limit)
+ if (frequency > desc->entries[i].limit)
continue;
break;
}
if (debug)
printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
- params->frequency, i, desc->count);
+ frequency, i, desc->count);
if (i == desc->count)
return -EINVAL;
- div = (params->frequency + desc->iffreq +
+ div = (frequency + desc->iffreq +
desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
buf[0] = div >> 8;
buf[1] = div & 0xff;
@@ -568,7 +565,7 @@ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
buf[3] = desc->entries[i].cb;
if (desc->set)
- desc->set(fe, buf, params);
+ desc->set(fe, buf);
if (debug)
printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -611,9 +608,9 @@ static int dvb_pll_sleep(struct dvb_frontend *fe)
return -EINVAL;
}
-static int dvb_pll_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int dvb_pll_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_pll_priv *priv = fe->tuner_priv;
u8 buf[4];
struct i2c_msg msg =
@@ -625,7 +622,8 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
if (priv->i2c == NULL)
return -EINVAL;
- if ((result = dvb_pll_configure(fe, buf, params)) < 0)
+ result = dvb_pll_configure(fe, buf, c->frequency);
+ if (result < 0)
return result;
else
frequency = result;
@@ -637,15 +635,15 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
}
priv->frequency = frequency;
- priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+ priv->bandwidth = c->bandwidth_hz;
return 0;
}
static int dvb_pll_calc_regs(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
u8 *buf, int buf_len)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_pll_priv *priv = fe->tuner_priv;
int result;
u32 frequency = 0;
@@ -653,7 +651,8 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
if (buf_len < 5)
return -EINVAL;
- if ((result = dvb_pll_configure(fe, buf+1, params)) < 0)
+ result = dvb_pll_configure(fe, buf + 1, c->frequency);
+ if (result < 0)
return result;
else
frequency = result;
@@ -661,7 +660,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
buf[0] = priv->pll_i2c_address;
priv->frequency = frequency;
- priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+ priv->bandwidth = c->bandwidth_hz;
return 5;
}
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
index a7fc7e53a551..dcfc902c8678 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -68,15 +68,18 @@ static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+/*
+ * Only needed if it actually reads something from the hardware
+ */
+static int dvb_dummy_fe_get_frontend(struct dvb_frontend *fe)
{
return 0;
}
-static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int dvb_dummy_fe_set_frontend(struct dvb_frontend *fe)
{
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -171,10 +174,9 @@ error:
}
static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "Dummy DVB-T",
- .type = FE_OFDM,
.frequency_min = 0,
.frequency_max = 863250000,
.frequency_stepsize = 62500,
@@ -203,10 +205,9 @@ static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = {
};
static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = {
-
+ .delsys = { SYS_DVBC_ANNEX_A },
.info = {
.name = "Dummy DVB-C",
- .type = FE_QAM,
.frequency_stepsize = 62500,
.frequency_min = 51000000,
.frequency_max = 858000000,
@@ -233,10 +234,9 @@ static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = {
};
static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "Dummy DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 250, /* kHz for QPSK frontends */
diff --git a/drivers/media/dvb/frontends/ec100.c b/drivers/media/dvb/frontends/ec100.c
index 2414dc6ee5d9..c56fddbf53b7 100644
--- a/drivers/media/dvb/frontends/ec100.c
+++ b/drivers/media/dvb/frontends/ec100.c
@@ -76,19 +76,19 @@ static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val)
return 0;
}
-static int ec100_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int ec100_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct ec100_state *state = fe->demodulator_priv;
int ret;
u8 tmp, tmp2;
- deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency,
- params->u.ofdm.bandwidth);
+ deb_info("%s: freq:%d bw:%d\n", __func__, c->frequency,
+ c->bandwidth_hz);
/* program tuner */
if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, params);
+ fe->ops.tuner_ops.set_params(fe);
ret = ec100_write_reg(state, 0x04, 0x06);
if (ret)
@@ -108,16 +108,16 @@ static int ec100_set_frontend(struct dvb_frontend *fe,
B 0x1b | 0xb7 | 0x00 | 0x49
B 0x1c | 0x55 | 0x64 | 0x72 */
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (c->bandwidth_hz) {
+ case 6000000:
tmp = 0xb7;
tmp2 = 0x55;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
tmp = 0x00;
tmp2 = 0x64;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
default:
tmp = 0x49;
tmp2 = 0x72;
@@ -306,9 +306,9 @@ error:
EXPORT_SYMBOL(ec100_attach);
static struct dvb_frontend_ops ec100_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "E3C EC100 DVB-T",
- .type = FE_OFDM,
.caps =
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
diff --git a/drivers/media/dvb/frontends/hd29l2.c b/drivers/media/dvb/frontends/hd29l2.c
new file mode 100644
index 000000000000..a00318190837
--- /dev/null
+++ b/drivers/media/dvb/frontends/hd29l2.c
@@ -0,0 +1,861 @@
+/*
+ * HDIC HD29L2 DMB-TH demodulator driver
+ *
+ * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
+ *
+ * Author: Antti Palosaari <crope@iki.fi>
+ *
+ * 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 "hd29l2_priv.h"
+
+int hd29l2_debug;
+module_param_named(debug, hd29l2_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+/* write multiple registers */
+static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
+{
+ int ret;
+ u8 buf[2 + len];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->cfg.i2c_addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ buf[0] = 0x00;
+ buf[1] = reg;
+ memcpy(&buf[2], val, len);
+
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* read multiple registers */
+static int hd29l2_rd_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
+{
+ int ret;
+ u8 buf[2] = { 0x00, reg };
+ struct i2c_msg msg[2] = {
+ {
+ .addr = priv->cfg.i2c_addr,
+ .flags = 0,
+ .len = 2,
+ .buf = buf,
+ }, {
+ .addr = priv->cfg.i2c_addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = val,
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret == 2) {
+ ret = 0;
+ } else {
+ warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* write single register */
+static int hd29l2_wr_reg(struct hd29l2_priv *priv, u8 reg, u8 val)
+{
+ return hd29l2_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int hd29l2_rd_reg(struct hd29l2_priv *priv, u8 reg, u8 *val)
+{
+ return hd29l2_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ /* no need for read if whole reg is written */
+ if (mask != 0xff) {
+ ret = hd29l2_rd_regs(priv, reg, &tmp, 1);
+ if (ret)
+ return ret;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ return hd29l2_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register with mask */
+int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask)
+{
+ int ret, i;
+ u8 tmp;
+
+ ret = hd29l2_rd_regs(priv, reg, &tmp, 1);
+ if (ret)
+ return ret;
+
+ tmp &= mask;
+
+ /* find position of the first bit */
+ for (i = 0; i < 8; i++) {
+ if ((mask >> i) & 0x01)
+ break;
+ }
+ *val = tmp >> i;
+
+ return 0;
+}
+
+static int hd29l2_soft_reset(struct hd29l2_priv *priv)
+{
+ int ret;
+ u8 tmp;
+
+ ret = hd29l2_rd_reg(priv, 0x26, &tmp);
+ if (ret)
+ goto err;
+
+ ret = hd29l2_wr_reg(priv, 0x26, 0x0d);
+ if (ret)
+ goto err;
+
+ usleep_range(10000, 20000);
+
+ ret = hd29l2_wr_reg(priv, 0x26, tmp);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int hd29l2_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ int ret, i;
+ struct hd29l2_priv *priv = fe->demodulator_priv;
+ u8 tmp;
+
+ dbg("%s: enable=%d", __func__, enable);
+
+ /* set tuner address for demod */
+ if (!priv->tuner_i2c_addr_programmed && enable) {
+ /* no need to set tuner address every time, once is enough */
+ ret = hd29l2_wr_reg(priv, 0x9d, priv->cfg.tuner_i2c_addr << 1);
+ if (ret)
+ goto err;
+
+ priv->tuner_i2c_addr_programmed = true;
+ }
+
+ /* open / close gate */
+ ret = hd29l2_wr_reg(priv, 0x9f, enable);
+ if (ret)
+ goto err;
+
+ /* wait demod ready */
+ for (i = 10; i; i--) {
+ ret = hd29l2_rd_reg(priv, 0x9e, &tmp);
+ if (ret)
+ goto err;
+
+ if (tmp == enable)
+ break;
+
+ usleep_range(5000, 10000);
+ }
+
+ dbg("%s: loop=%d", __func__, i);
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int hd29l2_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ int ret;
+ struct hd29l2_priv *priv = fe->demodulator_priv;
+ u8 buf[2];
+
+ *status = 0;
+
+ ret = hd29l2_rd_reg(priv, 0x05, &buf[0]);
+ if (ret)
+ goto err;
+
+ if (buf[0] & 0x01) {
+ /* full lock */
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_LOCK;
+ } else {
+ ret = hd29l2_rd_reg(priv, 0x0d, &buf[1]);
+ if (ret)
+ goto err;
+
+ if ((buf[1] & 0xfe) == 0x78)
+ /* partial lock */
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC;
+ }
+
+ priv->fe_status = *status;
+
+ return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int hd29l2_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ int ret;
+ struct hd29l2_priv *priv = fe->demodulator_priv;
+ u8 buf[2];
+ u16 tmp;
+
+ if (!(priv->fe_status & FE_HAS_LOCK)) {
+ *snr = 0;
+ ret = 0;
+ goto err;
+ }
+
+ ret = hd29l2_rd_regs(priv, 0x0b, buf, 2);
+ if (ret)
+ goto err;
+
+ tmp = (buf[0] << 8) | buf[1];
+
+ /* report SNR in dB * 10 */
+ #define LOG10_20736_24 72422627 /* log10(20736) << 24 */
+ if (tmp)
+ *snr = (LOG10_20736_24 - intlog10(tmp)) / ((1 << 24) / 100);
+ else
+ *snr = 0;
+
+ return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int hd29l2_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ int ret;
+ struct hd29l2_priv *priv = fe->demodulator_priv;
+ u8 buf[2];
+ u16 tmp;
+
+ *strength = 0;
+
+ ret = hd29l2_rd_regs(priv, 0xd5, buf, 2);
+ if (ret)
+ goto err;
+
+ tmp = buf[0] << 8 | buf[1];
+ tmp = ~tmp & 0x0fff;
+
+ /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
+ *strength = tmp * 0xffff / 0x0fff;
+
+ return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int hd29l2_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ int ret;
+ struct hd29l2_priv *priv = fe->demodulator_priv;
+ u8 buf[2];
+
+ if (!(priv->fe_status & FE_HAS_SYNC)) {
+ *ber = 0;
+ ret = 0;
+ goto err;
+ }
+
+ ret = hd29l2_rd_regs(priv, 0xd9, buf, 2);
+ if (ret) {
+ *ber = 0;
+ goto err;
+ }
+
+ /* LDPC BER */
+ *ber = ((buf[0] & 0x0f) << 8) | buf[1];
+
+ return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int hd29l2_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ /* no way to read? */
+ *ucblocks = 0;
+ return 0;
+}
+
+static enum dvbfe_search hd29l2_search(struct dvb_frontend *fe)
+{
+ int ret, i;
+ struct hd29l2_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u8 tmp, buf[3];
+ u8 modulation, carrier, guard_interval, interleave, code_rate;
+ u64 num64;
+ u32 if_freq, if_ctl;
+ bool auto_mode;
+
+ dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d " \
+ "modulation=%d inversion=%d fec_inner=%d guard_interval=%d",
+ __func__,
+ c->delivery_system, c->frequency, c->bandwidth_hz,
+ c->modulation, c->inversion, c->fec_inner, c->guard_interval);
+
+ /* as for now we detect always params automatically */
+ auto_mode = true;
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe);
+
+ /* get and program IF */
+ if (fe->ops.tuner_ops.get_if_frequency)
+ fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+ else
+ if_freq = 0;
+
+ if (if_freq) {
+ /* normal IF */
+
+ /* calc IF control value */
+ num64 = if_freq;
+ num64 *= 0x800000;
+ num64 = div_u64(num64, HD29L2_XTAL);
+ num64 -= 0x800000;
+ if_ctl = num64;
+
+ tmp = 0xfc; /* tuner type normal */
+ } else {
+ /* zero IF */
+ if_ctl = 0;
+ tmp = 0xfe; /* tuner type Zero-IF */
+ }
+
+ buf[0] = ((if_ctl >> 0) & 0xff);
+ buf[1] = ((if_ctl >> 8) & 0xff);
+ buf[2] = ((if_ctl >> 16) & 0xff);
+
+ /* program IF control */
+ ret = hd29l2_wr_regs(priv, 0x14, buf, 3);
+ if (ret)
+ goto err;
+
+ /* program tuner type */
+ ret = hd29l2_wr_reg(priv, 0xab, tmp);
+ if (ret)
+ goto err;
+
+ dbg("%s: if_freq=%d if_ctl=%x", __func__, if_freq, if_ctl);
+
+ if (auto_mode) {
+ /*
+ * use auto mode
+ */
+
+ /* disable quick mode */
+ ret = hd29l2_wr_reg_mask(priv, 0xac, 0 << 7, 0x80);
+ if (ret)
+ goto err;
+
+ ret = hd29l2_wr_reg_mask(priv, 0x82, 1 << 1, 0x02);
+ if (ret)
+ goto err;
+
+ /* enable auto mode */
+ ret = hd29l2_wr_reg_mask(priv, 0x7d, 1 << 6, 0x40);
+ if (ret)
+ goto err;
+
+ ret = hd29l2_wr_reg_mask(priv, 0x81, 1 << 3, 0x08);
+ if (ret)
+ goto err;
+
+ /* soft reset */
+ ret = hd29l2_soft_reset(priv);
+ if (ret)
+ goto err;
+
+ /* detect modulation */
+ for (i = 30; i; i--) {
+ msleep(100);
+
+ ret = hd29l2_rd_reg(priv, 0x0d, &tmp);
+ if (ret)
+ goto err;
+
+ if ((((tmp & 0xf0) >= 0x10) &&
+ ((tmp & 0x0f) == 0x08)) || (tmp >= 0x2c))
+ break;
+ }
+
+ dbg("%s: loop=%d", __func__, i);
+
+ if (i == 0)
+ /* detection failed */
+ return DVBFE_ALGO_SEARCH_FAILED;
+
+ /* read modulation */
+ ret = hd29l2_rd_reg_mask(priv, 0x7d, &modulation, 0x07);
+ if (ret)
+ goto err;
+ } else {
+ /*
+ * use manual mode
+ */
+
+ modulation = HD29L2_QAM64;
+ carrier = HD29L2_CARRIER_MULTI;
+ guard_interval = HD29L2_PN945;
+ interleave = HD29L2_INTERLEAVER_420;
+ code_rate = HD29L2_CODE_RATE_08;
+
+ tmp = (code_rate << 3) | modulation;
+ ret = hd29l2_wr_reg_mask(priv, 0x7d, tmp, 0x5f);
+ if (ret)
+ goto err;
+
+ tmp = (carrier << 2) | guard_interval;
+ ret = hd29l2_wr_reg_mask(priv, 0x81, tmp, 0x0f);
+ if (ret)
+ goto err;
+
+ tmp = interleave;
+ ret = hd29l2_wr_reg_mask(priv, 0x82, tmp, 0x03);
+ if (ret)
+ goto err;
+ }
+
+ /* ensure modulation validy */
+ /* 0=QAM4_NR, 1=QAM4, 2=QAM16, 3=QAM32, 4=QAM64 */
+ if (modulation > (ARRAY_SIZE(reg_mod_vals_tab[0].val) - 1)) {
+ dbg("%s: modulation=%d not valid", __func__, modulation);
+ goto err;
+ }
+
+ /* program registers according to modulation */
+ for (i = 0; i < ARRAY_SIZE(reg_mod_vals_tab); i++) {
+ ret = hd29l2_wr_reg(priv, reg_mod_vals_tab[i].reg,
+ reg_mod_vals_tab[i].val[modulation]);
+ if (ret)
+ goto err;
+ }
+
+ /* read guard interval */
+ ret = hd29l2_rd_reg_mask(priv, 0x81, &guard_interval, 0x03);
+ if (ret)
+ goto err;
+
+ /* read carrier mode */
+ ret = hd29l2_rd_reg_mask(priv, 0x81, &carrier, 0x04);
+ if (ret)
+ goto err;
+
+ dbg("%s: modulation=%d guard_interval=%d carrier=%d",
+ __func__, modulation, guard_interval, carrier);
+
+ if ((carrier == HD29L2_CARRIER_MULTI) && (modulation == HD29L2_QAM64) &&
+ (guard_interval == HD29L2_PN945)) {
+ dbg("%s: C=3780 && QAM64 && PN945", __func__);
+
+ ret = hd29l2_wr_reg(priv, 0x42, 0x33);
+ if (ret)
+ goto err;
+
+ ret = hd29l2_wr_reg(priv, 0xdd, 0x01);
+ if (ret)
+ goto err;
+ }
+
+ usleep_range(10000, 20000);
+
+ /* soft reset */
+ ret = hd29l2_soft_reset(priv);
+ if (ret)
+ goto err;
+
+ /* wait demod lock */
+ for (i = 30; i; i--) {
+ msleep(100);
+
+ /* read lock bit */
+ ret = hd29l2_rd_reg_mask(priv, 0x05, &tmp, 0x01);
+ if (ret)
+ goto err;
+
+ if (tmp)
+ break;
+ }
+
+ dbg("%s: loop=%d", __func__, i);
+
+ if (i == 0)
+ return DVBFE_ALGO_SEARCH_AGAIN;
+
+ return DVBFE_ALGO_SEARCH_SUCCESS;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static int hd29l2_get_frontend_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_CUSTOM;
+}
+
+static int hd29l2_get_frontend(struct dvb_frontend *fe)
+{
+ int ret;
+ struct hd29l2_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u8 buf[3];
+ u32 if_ctl;
+ char *str_constellation, *str_code_rate, *str_constellation_code_rate,
+ *str_guard_interval, *str_carrier, *str_guard_interval_carrier,
+ *str_interleave, *str_interleave_;
+
+ ret = hd29l2_rd_reg(priv, 0x7d, &buf[0]);
+ if (ret)
+ goto err;
+
+ ret = hd29l2_rd_regs(priv, 0x81, &buf[1], 2);
+ if (ret)
+ goto err;
+
+ /* constellation, 0x7d[2:0] */
+ switch ((buf[0] >> 0) & 0x07) {
+ case 0: /* QAM4NR */
+ str_constellation = "QAM4NR";
+ c->modulation = QAM_AUTO; /* FIXME */
+ break;
+ case 1: /* QAM4 */
+ str_constellation = "QAM4";
+ c->modulation = QPSK; /* FIXME */
+ break;
+ case 2:
+ str_constellation = "QAM16";
+ c->modulation = QAM_16;
+ break;
+ case 3:
+ str_constellation = "QAM32";
+ c->modulation = QAM_32;
+ break;
+ case 4:
+ str_constellation = "QAM64";
+ c->modulation = QAM_64;
+ break;
+ default:
+ str_constellation = "?";
+ }
+
+ /* LDPC code rate, 0x7d[4:3] */
+ switch ((buf[0] >> 3) & 0x03) {
+ case 0: /* 0.4 */
+ str_code_rate = "0.4";
+ c->fec_inner = FEC_AUTO; /* FIXME */
+ break;
+ case 1: /* 0.6 */
+ str_code_rate = "0.6";
+ c->fec_inner = FEC_3_5;
+ break;
+ case 2: /* 0.8 */
+ str_code_rate = "0.8";
+ c->fec_inner = FEC_4_5;
+ break;
+ default:
+ str_code_rate = "?";
+ }
+
+ /* constellation & code rate set, 0x7d[6] */
+ switch ((buf[0] >> 6) & 0x01) {
+ case 0:
+ str_constellation_code_rate = "manual";
+ break;
+ case 1:
+ str_constellation_code_rate = "auto";
+ break;
+ default:
+ str_constellation_code_rate = "?";
+ }
+
+ /* frame header, 0x81[1:0] */
+ switch ((buf[1] >> 0) & 0x03) {
+ case 0: /* PN945 */
+ str_guard_interval = "PN945";
+ c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
+ break;
+ case 1: /* PN595 */
+ str_guard_interval = "PN595";
+ c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
+ break;
+ case 2: /* PN420 */
+ str_guard_interval = "PN420";
+ c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
+ break;
+ default:
+ str_guard_interval = "?";
+ }
+
+ /* carrier, 0x81[2] */
+ switch ((buf[1] >> 2) & 0x01) {
+ case 0:
+ str_carrier = "C=1";
+ break;
+ case 1:
+ str_carrier = "C=3780";
+ break;
+ default:
+ str_carrier = "?";
+ }
+
+ /* frame header & carrier set, 0x81[3] */
+ switch ((buf[1] >> 3) & 0x01) {
+ case 0:
+ str_guard_interval_carrier = "manual";
+ break;
+ case 1:
+ str_guard_interval_carrier = "auto";
+ break;
+ default:
+ str_guard_interval_carrier = "?";
+ }
+
+ /* interleave, 0x82[0] */
+ switch ((buf[2] >> 0) & 0x01) {
+ case 0:
+ str_interleave = "M=720";
+ break;
+ case 1:
+ str_interleave = "M=240";
+ break;
+ default:
+ str_interleave = "?";
+ }
+
+ /* interleave set, 0x82[1] */
+ switch ((buf[2] >> 1) & 0x01) {
+ case 0:
+ str_interleave_ = "manual";
+ break;
+ case 1:
+ str_interleave_ = "auto";
+ break;
+ default:
+ str_interleave_ = "?";
+ }
+
+ /*
+ * We can read out current detected NCO and use that value next
+ * time instead of calculating new value from targed IF.
+ * I think it will not effect receiver sensitivity but gaining lock
+ * after tune could be easier...
+ */
+ ret = hd29l2_rd_regs(priv, 0xb1, &buf[0], 3);
+ if (ret)
+ goto err;
+
+ if_ctl = (buf[0] << 16) | ((buf[1] - 7) << 8) | buf[2];
+
+ dbg("%s: %s %s %s | %s %s %s | %s %s | NCO=%06x", __func__,
+ str_constellation, str_code_rate, str_constellation_code_rate,
+ str_guard_interval, str_carrier, str_guard_interval_carrier,
+ str_interleave, str_interleave_, if_ctl);
+
+ return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int hd29l2_init(struct dvb_frontend *fe)
+{
+ int ret, i;
+ struct hd29l2_priv *priv = fe->demodulator_priv;
+ u8 tmp;
+ static const struct reg_val tab[] = {
+ { 0x3a, 0x06 },
+ { 0x3b, 0x03 },
+ { 0x3c, 0x04 },
+ { 0xaf, 0x06 },
+ { 0xb0, 0x1b },
+ { 0x80, 0x64 },
+ { 0x10, 0x38 },
+ };
+
+ dbg("%s:", __func__);
+
+ /* reset demod */
+ /* it is recommended to HW reset chip using RST_N pin */
+ if (fe->callback) {
+ ret = fe->callback(fe, DVB_FRONTEND_COMPONENT_DEMOD, 0, 0);
+ if (ret)
+ goto err;
+
+ /* reprogramming needed because HW reset clears registers */
+ priv->tuner_i2c_addr_programmed = false;
+ }
+
+ /* init */
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = hd29l2_wr_reg(priv, tab[i].reg, tab[i].val);
+ if (ret)
+ goto err;
+ }
+
+ /* TS params */
+ ret = hd29l2_rd_reg(priv, 0x36, &tmp);
+ if (ret)
+ goto err;
+
+ tmp &= 0x1b;
+ tmp |= priv->cfg.ts_mode;
+ ret = hd29l2_wr_reg(priv, 0x36, tmp);
+ if (ret)
+ goto err;
+
+ ret = hd29l2_rd_reg(priv, 0x31, &tmp);
+ tmp &= 0xef;
+
+ if (!(priv->cfg.ts_mode >> 7))
+ /* set b4 for serial TS */
+ tmp |= 0x10;
+
+ ret = hd29l2_wr_reg(priv, 0x31, tmp);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static void hd29l2_release(struct dvb_frontend *fe)
+{
+ struct hd29l2_priv *priv = fe->demodulator_priv;
+ kfree(priv);
+}
+
+static struct dvb_frontend_ops hd29l2_ops;
+
+struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
+ struct i2c_adapter *i2c)
+{
+ int ret;
+ struct hd29l2_priv *priv = NULL;
+ u8 tmp;
+
+ /* allocate memory for the internal state */
+ priv = kzalloc(sizeof(struct hd29l2_priv), GFP_KERNEL);
+ if (priv == NULL)
+ goto err;
+
+ /* setup the state */
+ priv->i2c = i2c;
+ memcpy(&priv->cfg, config, sizeof(struct hd29l2_config));
+
+
+ /* check if the demod is there */
+ ret = hd29l2_rd_reg(priv, 0x00, &tmp);
+ if (ret)
+ goto err;
+
+ /* create dvb_frontend */
+ memcpy(&priv->fe.ops, &hd29l2_ops, sizeof(struct dvb_frontend_ops));
+ priv->fe.demodulator_priv = priv;
+
+ return &priv->fe;
+err:
+ kfree(priv);
+ return NULL;
+}
+EXPORT_SYMBOL(hd29l2_attach);
+
+static struct dvb_frontend_ops hd29l2_ops = {
+ .delsys = { SYS_DVBT },
+ .info = {
+ .name = "HDIC HD29L2 DMB-TH",
+ .frequency_min = 474000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 10000,
+ .caps = FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_BANDWIDTH_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_RECOVER
+ },
+
+ .release = hd29l2_release,
+
+ .init = hd29l2_init,
+
+ .get_frontend_algo = hd29l2_get_frontend_algo,
+ .search = hd29l2_search,
+ .get_frontend = hd29l2_get_frontend,
+
+ .read_status = hd29l2_read_status,
+ .read_snr = hd29l2_read_snr,
+ .read_signal_strength = hd29l2_read_signal_strength,
+ .read_ber = hd29l2_read_ber,
+ .read_ucblocks = hd29l2_read_ucblocks,
+
+ .i2c_gate_ctrl = hd29l2_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("HDIC HD29L2 DMB-TH demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/hd29l2.h b/drivers/media/dvb/frontends/hd29l2.h
new file mode 100644
index 000000000000..a7a64431364d
--- /dev/null
+++ b/drivers/media/dvb/frontends/hd29l2.h
@@ -0,0 +1,66 @@
+/*
+ * HDIC HD29L2 DMB-TH demodulator driver
+ *
+ * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
+ *
+ * Author: Antti Palosaari <crope@iki.fi>
+ *
+ * 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 HD29L2_H
+#define HD29L2_H
+
+#include <linux/dvb/frontend.h>
+
+struct hd29l2_config {
+ /*
+ * demodulator I2C address
+ */
+ u8 i2c_addr;
+
+ /*
+ * tuner I2C address
+ * only needed when tuner is behind demod I2C-gate
+ */
+ u8 tuner_i2c_addr;
+
+ /*
+ * TS settings
+ */
+#define HD29L2_TS_SERIAL 0x00
+#define HD29L2_TS_PARALLEL 0x80
+#define HD29L2_TS_CLK_NORMAL 0x40
+#define HD29L2_TS_CLK_INVERTED 0x00
+#define HD29L2_TS_CLK_GATED 0x20
+#define HD29L2_TS_CLK_FREE 0x00
+ u8 ts_mode;
+};
+
+
+#if defined(CONFIG_DVB_HD29L2) || \
+ (defined(CONFIG_DVB_HD29L2_MODULE) && defined(MODULE))
+extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *hd29l2_attach(
+const struct hd29l2_config *config, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* HD29L2_H */
diff --git a/drivers/media/dvb/frontends/hd29l2_priv.h b/drivers/media/dvb/frontends/hd29l2_priv.h
new file mode 100644
index 000000000000..ba16dc3ec2bd
--- /dev/null
+++ b/drivers/media/dvb/frontends/hd29l2_priv.h
@@ -0,0 +1,314 @@
+/*
+ * HDIC HD29L2 DMB-TH demodulator driver
+ *
+ * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
+ *
+ * Author: Antti Palosaari <crope@iki.fi>
+ *
+ * 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 HD29L2_PRIV
+#define HD29L2_PRIV
+
+#include <linux/dvb/version.h>
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "hd29l2.h"
+
+#define LOG_PREFIX "hd29l2"
+
+#undef dbg
+#define dbg(f, arg...) \
+ if (hd29l2_debug) \
+ printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#define HD29L2_XTAL 30400000 /* Hz */
+
+
+#define HD29L2_QAM4NR 0x00
+#define HD29L2_QAM4 0x01
+#define HD29L2_QAM16 0x02
+#define HD29L2_QAM32 0x03
+#define HD29L2_QAM64 0x04
+
+#define HD29L2_CODE_RATE_04 0x00
+#define HD29L2_CODE_RATE_06 0x08
+#define HD29L2_CODE_RATE_08 0x10
+
+#define HD29L2_PN945 0x00
+#define HD29L2_PN595 0x01
+#define HD29L2_PN420 0x02
+
+#define HD29L2_CARRIER_SINGLE 0x00
+#define HD29L2_CARRIER_MULTI 0x01
+
+#define HD29L2_INTERLEAVER_720 0x00
+#define HD29L2_INTERLEAVER_420 0x01
+
+struct reg_val {
+ u8 reg;
+ u8 val;
+};
+
+struct reg_mod_vals {
+ u8 reg;
+ u8 val[5];
+};
+
+struct hd29l2_priv {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend fe;
+ struct hd29l2_config cfg;
+ u8 tuner_i2c_addr_programmed:1;
+
+ fe_status_t fe_status;
+};
+
+static const struct reg_mod_vals reg_mod_vals_tab[] = {
+ /* REG, QAM4NR, QAM4,QAM16,QAM32,QAM64 */
+ { 0x01, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+ { 0x02, { 0x07, 0x07, 0x07, 0x07, 0x07 } },
+ { 0x03, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+ { 0x04, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x05, { 0x61, 0x60, 0x60, 0x61, 0x60 } },
+ { 0x06, { 0xff, 0xff, 0xff, 0xff, 0xff } },
+ { 0x07, { 0xff, 0xff, 0xff, 0xff, 0xff } },
+ { 0x08, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x09, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x0a, { 0x15, 0x15, 0x03, 0x03, 0x03 } },
+ { 0x0d, { 0x78, 0x78, 0x88, 0x78, 0x78 } },
+ { 0x0e, { 0xa0, 0x90, 0xa0, 0xa0, 0xa0 } },
+ { 0x0f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x10, { 0xa0, 0xa0, 0x58, 0x38, 0x38 } },
+ { 0x11, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x12, { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a } },
+ { 0x13, { 0xa2, 0xa2, 0xa2, 0xa2, 0xa2 } },
+ { 0x17, { 0x40, 0x40, 0x40, 0x40, 0x40 } },
+ { 0x18, { 0x21, 0x21, 0x42, 0x52, 0x42 } },
+ { 0x19, { 0x21, 0x21, 0x62, 0x72, 0x62 } },
+ { 0x1a, { 0x32, 0x43, 0xa9, 0xb9, 0xa9 } },
+ { 0x1b, { 0x32, 0x43, 0xb9, 0xd8, 0xb9 } },
+ { 0x1c, { 0x02, 0x02, 0x03, 0x02, 0x03 } },
+ { 0x1d, { 0x0c, 0x0c, 0x01, 0x02, 0x02 } },
+ { 0x1e, { 0x02, 0x02, 0x02, 0x01, 0x02 } },
+ { 0x1f, { 0x02, 0x02, 0x01, 0x02, 0x04 } },
+ { 0x20, { 0x01, 0x02, 0x01, 0x01, 0x01 } },
+ { 0x21, { 0x08, 0x08, 0x0a, 0x0a, 0x0a } },
+ { 0x22, { 0x06, 0x06, 0x04, 0x05, 0x05 } },
+ { 0x23, { 0x06, 0x06, 0x05, 0x03, 0x05 } },
+ { 0x24, { 0x08, 0x08, 0x05, 0x07, 0x07 } },
+ { 0x25, { 0x16, 0x10, 0x10, 0x0a, 0x10 } },
+ { 0x26, { 0x14, 0x14, 0x04, 0x04, 0x04 } },
+ { 0x27, { 0x58, 0x58, 0x58, 0x5c, 0x58 } },
+ { 0x28, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+ { 0x29, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+ { 0x2a, { 0x08, 0x0a, 0x08, 0x08, 0x08 } },
+ { 0x2b, { 0x08, 0x08, 0x08, 0x08, 0x08 } },
+ { 0x2c, { 0x06, 0x06, 0x06, 0x06, 0x06 } },
+ { 0x2d, { 0x05, 0x06, 0x06, 0x06, 0x06 } },
+ { 0x2e, { 0x21, 0x21, 0x21, 0x21, 0x21 } },
+ { 0x2f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x30, { 0x14, 0x14, 0x14, 0x14, 0x14 } },
+ { 0x33, { 0xb7, 0xb7, 0xb7, 0xb7, 0xb7 } },
+ { 0x34, { 0x81, 0x81, 0x81, 0x81, 0x81 } },
+ { 0x35, { 0x80, 0x80, 0x80, 0x80, 0x80 } },
+ { 0x37, { 0x70, 0x70, 0x70, 0x70, 0x70 } },
+ { 0x38, { 0x04, 0x04, 0x02, 0x02, 0x02 } },
+ { 0x39, { 0x07, 0x07, 0x05, 0x05, 0x05 } },
+ { 0x3a, { 0x06, 0x06, 0x06, 0x06, 0x06 } },
+ { 0x3b, { 0x03, 0x03, 0x03, 0x03, 0x03 } },
+ { 0x3c, { 0x07, 0x06, 0x04, 0x04, 0x04 } },
+ { 0x3d, { 0xf0, 0xf0, 0xf0, 0xf0, 0x80 } },
+ { 0x3e, { 0x60, 0x60, 0x60, 0x60, 0xff } },
+ { 0x3f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x40, { 0x5b, 0x5b, 0x5b, 0x57, 0x50 } },
+ { 0x41, { 0x30, 0x30, 0x30, 0x30, 0x18 } },
+ { 0x42, { 0x20, 0x20, 0x20, 0x00, 0x30 } },
+ { 0x43, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x44, { 0x3f, 0x3f, 0x3f, 0x3f, 0x3f } },
+ { 0x45, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x46, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+ { 0x47, { 0x00, 0x00, 0x95, 0x00, 0x95 } },
+ { 0x48, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } },
+ { 0x49, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } },
+ { 0x4a, { 0x40, 0x40, 0x33, 0x11, 0x11 } },
+ { 0x4b, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+ { 0x4c, { 0x40, 0x40, 0x99, 0x11, 0x11 } },
+ { 0x4d, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+ { 0x4e, { 0x40, 0x40, 0x66, 0x77, 0x77 } },
+ { 0x4f, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+ { 0x50, { 0x40, 0x40, 0x88, 0x33, 0x11 } },
+ { 0x51, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+ { 0x52, { 0x40, 0x40, 0x88, 0x02, 0x02 } },
+ { 0x53, { 0x40, 0x40, 0x00, 0x02, 0x02 } },
+ { 0x54, { 0x00, 0x00, 0x88, 0x33, 0x33 } },
+ { 0x55, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+ { 0x56, { 0x00, 0x00, 0x00, 0x0b, 0x00 } },
+ { 0x57, { 0x40, 0x40, 0x0a, 0x0b, 0x0a } },
+ { 0x58, { 0xaa, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x59, { 0x7a, 0x40, 0x02, 0x02, 0x02 } },
+ { 0x5a, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+ { 0x5b, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+ { 0x5c, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+ { 0x5d, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+ { 0x5e, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } },
+ { 0x5f, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } },
+ { 0x60, { 0x40, 0x40, 0x00, 0x30, 0x30 } },
+ { 0x61, { 0x40, 0x40, 0x10, 0x30, 0x30 } },
+ { 0x62, { 0x40, 0x40, 0x00, 0x30, 0x30 } },
+ { 0x63, { 0x40, 0x40, 0x05, 0x30, 0x30 } },
+ { 0x64, { 0x40, 0x40, 0x06, 0x00, 0x30 } },
+ { 0x65, { 0x40, 0x40, 0x06, 0x08, 0x30 } },
+ { 0x66, { 0x40, 0x40, 0x00, 0x00, 0x20 } },
+ { 0x67, { 0x40, 0x40, 0x01, 0x04, 0x20 } },
+ { 0x68, { 0x00, 0x00, 0x30, 0x00, 0x20 } },
+ { 0x69, { 0xa0, 0xa0, 0x00, 0x08, 0x20 } },
+ { 0x6a, { 0x00, 0x00, 0x30, 0x00, 0x25 } },
+ { 0x6b, { 0xa0, 0xa0, 0x00, 0x06, 0x25 } },
+ { 0x6c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x6d, { 0xa0, 0x60, 0x0c, 0x03, 0x0c } },
+ { 0x6e, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x6f, { 0xa0, 0x60, 0x04, 0x01, 0x04 } },
+ { 0x70, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } },
+ { 0x71, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } },
+ { 0x72, { 0x58, 0x58, 0xff, 0xff, 0xff } },
+ { 0x73, { 0x58, 0x58, 0xff, 0xff, 0xff } },
+ { 0x74, { 0x06, 0x06, 0x09, 0x05, 0x05 } },
+ { 0x75, { 0x06, 0x06, 0x0a, 0x10, 0x10 } },
+ { 0x76, { 0x10, 0x10, 0x06, 0x0a, 0x0a } },
+ { 0x77, { 0x12, 0x18, 0x28, 0x10, 0x28 } },
+ { 0x78, { 0xf8, 0xf8, 0xf8, 0xf8, 0xf8 } },
+ { 0x79, { 0x15, 0x15, 0x03, 0x03, 0x03 } },
+ { 0x7a, { 0x02, 0x02, 0x01, 0x04, 0x03 } },
+ { 0x7b, { 0x01, 0x02, 0x03, 0x03, 0x03 } },
+ { 0x7c, { 0x28, 0x28, 0x28, 0x28, 0x28 } },
+ { 0x7f, { 0x25, 0x92, 0x5f, 0x17, 0x2d } },
+ { 0x80, { 0x64, 0x64, 0x64, 0x74, 0x64 } },
+ { 0x83, { 0x06, 0x03, 0x04, 0x04, 0x04 } },
+ { 0x84, { 0xff, 0xff, 0xff, 0xff, 0xff } },
+ { 0x85, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
+ { 0x86, { 0x00, 0x00, 0x11, 0x11, 0x11 } },
+ { 0x87, { 0x03, 0x03, 0x03, 0x03, 0x03 } },
+ { 0x88, { 0x09, 0x09, 0x09, 0x09, 0x09 } },
+ { 0x89, { 0x20, 0x20, 0x30, 0x20, 0x20 } },
+ { 0x8a, { 0x03, 0x03, 0x02, 0x03, 0x02 } },
+ { 0x8b, { 0x00, 0x07, 0x09, 0x00, 0x09 } },
+ { 0x8c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x8d, { 0x4f, 0x4f, 0x4f, 0x3f, 0x4f } },
+ { 0x8e, { 0xf0, 0xf0, 0x60, 0xf0, 0xa0 } },
+ { 0x8f, { 0xe8, 0xe8, 0xe8, 0xe8, 0xe8 } },
+ { 0x90, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+ { 0x91, { 0x40, 0x40, 0x70, 0x70, 0x10 } },
+ { 0x92, { 0x00, 0x00, 0x00, 0x00, 0x04 } },
+ { 0x93, { 0x60, 0x60, 0x60, 0x60, 0x60 } },
+ { 0x94, { 0x00, 0x00, 0x00, 0x00, 0x03 } },
+ { 0x95, { 0x09, 0x09, 0x47, 0x47, 0x47 } },
+ { 0x96, { 0x80, 0xa0, 0xa0, 0x40, 0xa0 } },
+ { 0x97, { 0x60, 0x60, 0x60, 0x60, 0x60 } },
+ { 0x98, { 0x50, 0x50, 0x50, 0x30, 0x50 } },
+ { 0x99, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+ { 0x9a, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0x9b, { 0x40, 0x40, 0x40, 0x30, 0x40 } },
+ { 0x9c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xa0, { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 } },
+ { 0xa1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xa2, { 0x30, 0x30, 0x00, 0x30, 0x00 } },
+ { 0xa3, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xa4, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xa5, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xa6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xa7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xa8, { 0x77, 0x77, 0x77, 0x77, 0x77 } },
+ { 0xa9, { 0x02, 0x02, 0x02, 0x02, 0x02 } },
+ { 0xaa, { 0x40, 0x40, 0x40, 0x40, 0x40 } },
+ { 0xac, { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f } },
+ { 0xad, { 0x14, 0x14, 0x14, 0x14, 0x14 } },
+ { 0xae, { 0x78, 0x78, 0x78, 0x78, 0x78 } },
+ { 0xaf, { 0x06, 0x06, 0x06, 0x06, 0x07 } },
+ { 0xb0, { 0x1b, 0x1b, 0x1b, 0x19, 0x1b } },
+ { 0xb1, { 0x18, 0x17, 0x17, 0x18, 0x17 } },
+ { 0xb2, { 0x35, 0x82, 0x82, 0x38, 0x82 } },
+ { 0xb3, { 0xb6, 0xce, 0xc7, 0x5c, 0xb0 } },
+ { 0xb4, { 0x3f, 0x3e, 0x3e, 0x3f, 0x3e } },
+ { 0xb5, { 0x70, 0x58, 0x50, 0x68, 0x50 } },
+ { 0xb6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xb7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xb8, { 0x03, 0x03, 0x01, 0x01, 0x01 } },
+ { 0xb9, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xba, { 0x06, 0x06, 0x0a, 0x05, 0x0a } },
+ { 0xbb, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xbc, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xbd, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xbe, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xbf, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xc0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xc1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xc2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xc3, { 0x00, 0x00, 0x88, 0x66, 0x88 } },
+ { 0xc4, { 0x10, 0x10, 0x00, 0x00, 0x00 } },
+ { 0xc5, { 0x00, 0x00, 0x44, 0x60, 0x44 } },
+ { 0xc6, { 0x10, 0x0a, 0x00, 0x00, 0x00 } },
+ { 0xc7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xc8, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xc9, { 0x90, 0x04, 0x00, 0x00, 0x00 } },
+ { 0xca, { 0x90, 0x08, 0x01, 0x01, 0x01 } },
+ { 0xcb, { 0xa0, 0x04, 0x00, 0x44, 0x00 } },
+ { 0xcc, { 0xa0, 0x10, 0x03, 0x00, 0x03 } },
+ { 0xcd, { 0x06, 0x06, 0x06, 0x05, 0x06 } },
+ { 0xce, { 0x05, 0x05, 0x01, 0x01, 0x01 } },
+ { 0xcf, { 0x40, 0x20, 0x18, 0x18, 0x18 } },
+ { 0xd0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xd1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xd2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xd3, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xd4, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
+ { 0xd5, { 0x05, 0x05, 0x05, 0x03, 0x05 } },
+ { 0xd6, { 0xac, 0x22, 0xca, 0x8f, 0xca } },
+ { 0xd7, { 0x20, 0x20, 0x20, 0x20, 0x20 } },
+ { 0xd8, { 0x01, 0x01, 0x01, 0x01, 0x01 } },
+ { 0xd9, { 0x00, 0x00, 0x0f, 0x00, 0x0f } },
+ { 0xda, { 0x00, 0xff, 0xff, 0x0e, 0xff } },
+ { 0xdb, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+ { 0xdc, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+ { 0xdd, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
+ { 0xde, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+ { 0xdf, { 0x42, 0x42, 0x44, 0x44, 0x04 } },
+ { 0xe0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xe1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xe2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xe3, { 0x00, 0x00, 0x26, 0x06, 0x26 } },
+ { 0xe4, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xe5, { 0x01, 0x0a, 0x01, 0x01, 0x01 } },
+ { 0xe6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xe7, { 0x08, 0x08, 0x08, 0x08, 0x08 } },
+ { 0xe8, { 0x63, 0x63, 0x63, 0x63, 0x63 } },
+ { 0xe9, { 0x59, 0x59, 0x59, 0x59, 0x59 } },
+ { 0xea, { 0x80, 0x80, 0x20, 0x80, 0x80 } },
+ { 0xeb, { 0x37, 0x37, 0x78, 0x37, 0x77 } },
+ { 0xec, { 0x1f, 0x1f, 0x25, 0x25, 0x25 } },
+ { 0xed, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+ { 0xee, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { 0xef, { 0x70, 0x70, 0x58, 0x38, 0x58 } },
+ { 0xf0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+};
+
+#endif /* HD29L2_PRIV */
diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb/frontends/it913x-fe-priv.h
index 1c6fb4b66255..eb6fd8aebdb3 100644
--- a/drivers/media/dvb/frontends/it913x-fe-priv.h
+++ b/drivers/media/dvb/frontends/it913x-fe-priv.h
@@ -22,126 +22,126 @@ struct adctable { u32 adcFrequency;
/* clock and coeff tables only table 3 is used with IT9137*/
/* TODO other tables relate AF9035 may be removed */
static struct adctable tab1[] = {
- { 20156250, BANDWIDTH_6_MHZ,
+ { 20156250, 6000000,
0x02b8ba6e, 0x015c5d37, 0x00ae340d, 0x00ae2e9b, 0x00ae292a,
0x015c5d37, 0x00ae2e9b, 0x0057174e, 0x02f1, 0x015c },
- { 20156250, BANDWIDTH_7_MHZ,
+ { 20156250, 7000000,
0x032cd980, 0x01966cc0, 0x00cb3cba, 0x00cb3660, 0x00cb3007,
0x01966cc0, 0x00cb3660, 0x00659b30, 0x0285, 0x0196 },
- { 20156250, BANDWIDTH_8_MHZ,
+ { 20156250, 8000000,
0x03a0f893, 0x01d07c49, 0x00e84567, 0x00e83e25, 0x00e836e3,
0x01d07c49, 0x00e83e25, 0x00741f12, 0x0234, 0x01d0 },
- { 20156250, BANDWIDTH_5_MHZ,
+ { 20156250, 5000000,
0x02449b5c, 0x01224dae, 0x00912b60, 0x009126d7, 0x0091224e,
0x01224dae, 0x009126d7, 0x0048936b, 0x0387, 0x0122 }
};
static struct adctable tab2[] = {
- { 20187500, BANDWIDTH_6_MHZ,
+ { 20187500, 6000000,
0x02b7a654, 0x015bd32a, 0x00adef04, 0x00ade995, 0x00ade426,
0x015bd32a, 0x00ade995, 0x0056f4ca, 0x02f2, 0x015c },
- { 20187500, BANDWIDTH_7_MHZ,
+ { 20187500, 7000000,
0x032b9761, 0x0195cbb1, 0x00caec30, 0x00cae5d8, 0x00cadf81,
0x0195cbb1, 0x00cae5d8, 0x006572ec, 0x0286, 0x0196 },
- { 20187500, BANDWIDTH_8_MHZ,
+ { 20187500, 8000000,
0x039f886f, 0x01cfc438, 0x00e7e95b, 0x00e7e21c, 0x00e7dadd,
0x01cfc438, 0x00e7e21c, 0x0073f10e, 0x0235, 0x01d0 },
- { 20187500, BANDWIDTH_5_MHZ,
+ { 20187500, 5000000,
0x0243b546, 0x0121daa3, 0x0090f1d9, 0x0090ed51, 0x0090e8ca,
0x0121daa3, 0x0090ed51, 0x004876a9, 0x0388, 0x0122 }
};
static struct adctable tab3[] = {
- { 20250000, BANDWIDTH_6_MHZ,
+ { 20250000, 6000000,
0x02b580ad, 0x015ac057, 0x00ad6597, 0x00ad602b, 0x00ad5ac1,
0x015ac057, 0x00ad602b, 0x0056b016, 0x02f4, 0x015b },
- { 20250000, BANDWIDTH_7_MHZ,
+ { 20250000, 7000000,
0x03291620, 0x01948b10, 0x00ca4bda, 0x00ca4588, 0x00ca3f36,
0x01948b10, 0x00ca4588, 0x006522c4, 0x0288, 0x0195 },
- { 20250000, BANDWIDTH_8_MHZ,
+ { 20250000, 8000000,
0x039cab92, 0x01ce55c9, 0x00e7321e, 0x00e72ae4, 0x00e723ab,
0x01ce55c9, 0x00e72ae4, 0x00739572, 0x0237, 0x01ce },
- { 20250000, BANDWIDTH_5_MHZ,
+ { 20250000, 5000000,
0x0241eb3b, 0x0120f59e, 0x00907f53, 0x00907acf, 0x0090764b,
0x0120f59e, 0x00907acf, 0x00483d67, 0x038b, 0x0121 }
};
static struct adctable tab4[] = {
- { 20583333, BANDWIDTH_6_MHZ,
+ { 20583333, 6000000,
0x02aa4598, 0x015522cc, 0x00aa96bb, 0x00aa9166, 0x00aa8c12,
0x015522cc, 0x00aa9166, 0x005548b3, 0x0300, 0x0155 },
- { 20583333, BANDWIDTH_7_MHZ,
+ { 20583333, 7000000,
0x031bfbdc, 0x018dfdee, 0x00c7052f, 0x00c6fef7, 0x00c6f8bf,
0x018dfdee, 0x00c6fef7, 0x00637f7b, 0x0293, 0x018e },
- { 20583333, BANDWIDTH_8_MHZ,
+ { 20583333, 8000000,
0x038db21f, 0x01c6d910, 0x00e373a3, 0x00e36c88, 0x00e3656d,
0x01c6d910, 0x00e36c88, 0x0071b644, 0x0240, 0x01c7 },
- { 20583333, BANDWIDTH_5_MHZ,
+ { 20583333, 5000000,
0x02388f54, 0x011c47aa, 0x008e2846, 0x008e23d5, 0x008e1f64,
0x011c47aa, 0x008e23d5, 0x004711ea, 0x039a, 0x011c }
};
static struct adctable tab5[] = {
- { 20416667, BANDWIDTH_6_MHZ,
+ { 20416667, 6000000,
0x02afd765, 0x0157ebb3, 0x00abfb39, 0x00abf5d9, 0x00abf07a,
0x0157ebb3, 0x00abf5d9, 0x0055faed, 0x02fa, 0x0158 },
- { 20416667, BANDWIDTH_7_MHZ,
+ { 20416667, 7000000,
0x03227b4b, 0x01913da6, 0x00c8a518, 0x00c89ed3, 0x00c8988e,
0x01913da6, 0x00c89ed3, 0x00644f69, 0x028d, 0x0191 },
- { 20416667, BANDWIDTH_8_MHZ,
+ { 20416667, 8000000,
0x03951f32, 0x01ca8f99, 0x00e54ef7, 0x00e547cc, 0x00e540a2,
0x01ca8f99, 0x00e547cc, 0x0072a3e6, 0x023c, 0x01cb },
- { 20416667, BANDWIDTH_5_MHZ,
+ { 20416667, 5000000,
0x023d337f, 0x011e99c0, 0x008f515a, 0x008f4ce0, 0x008f4865,
0x011e99c0, 0x008f4ce0, 0x0047a670, 0x0393, 0x011f }
};
static struct adctable tab6[] = {
- { 20480000, BANDWIDTH_6_MHZ,
+ { 20480000, 6000000,
0x02adb6db, 0x0156db6e, 0x00ab7312, 0x00ab6db7, 0x00ab685c,
0x0156db6e, 0x00ab6db7, 0x0055b6db, 0x02fd, 0x0157 },
- { 20480000, BANDWIDTH_7_MHZ,
+ { 20480000, 7000000,
0x03200000, 0x01900000, 0x00c80640, 0x00c80000, 0x00c7f9c0,
0x01900000, 0x00c80000, 0x00640000, 0x028f, 0x0190 },
- { 20480000, BANDWIDTH_8_MHZ,
+ { 20480000, 8000000,
0x03924925, 0x01c92492, 0x00e4996e, 0x00e49249, 0x00e48b25,
0x01c92492, 0x00e49249, 0x00724925, 0x023d, 0x01c9 },
- { 20480000, BANDWIDTH_5_MHZ,
+ { 20480000, 5000000,
0x023b6db7, 0x011db6db, 0x008edfe5, 0x008edb6e, 0x008ed6f7,
0x011db6db, 0x008edb6e, 0x00476db7, 0x0396, 0x011e }
};
static struct adctable tab7[] = {
- { 20500000, BANDWIDTH_6_MHZ,
+ { 20500000, 6000000,
0x02ad0b99, 0x015685cc, 0x00ab4840, 0x00ab42e6, 0x00ab3d8c,
0x015685cc, 0x00ab42e6, 0x0055a173, 0x02fd, 0x0157 },
- { 20500000, BANDWIDTH_7_MHZ,
+ { 20500000, 7000000,
0x031f3832, 0x018f9c19, 0x00c7d44b, 0x00c7ce0c, 0x00c7c7ce,
0x018f9c19, 0x00c7ce0c, 0x0063e706, 0x0290, 0x0190 },
- { 20500000, BANDWIDTH_8_MHZ,
+ { 20500000, 8000000,
0x039164cb, 0x01c8b266, 0x00e46056, 0x00e45933, 0x00e45210,
0x01c8b266, 0x00e45933, 0x00722c99, 0x023e, 0x01c9 },
- { 20500000, BANDWIDTH_5_MHZ,
+ { 20500000, 5000000,
0x023adeff, 0x011d6f80, 0x008ebc36, 0x008eb7c0, 0x008eb34a,
0x011d6f80, 0x008eb7c0, 0x00475be0, 0x0396, 0x011d }
};
static struct adctable tab8[] = {
- { 20625000, BANDWIDTH_6_MHZ,
+ { 20625000, 6000000,
0x02a8e4bd, 0x0154725e, 0x00aa3e81, 0x00aa392f, 0x00aa33de,
0x0154725e, 0x00aa392f, 0x00551c98, 0x0302, 0x0154 },
- { 20625000, BANDWIDTH_7_MHZ,
+ { 20625000, 7000000,
0x031a6032, 0x018d3019, 0x00c69e41, 0x00c6980c, 0x00c691d8,
0x018d3019, 0x00c6980c, 0x00634c06, 0x0294, 0x018d },
- { 20625000, BANDWIDTH_8_MHZ,
+ { 20625000, 8000000,
0x038bdba6, 0x01c5edd3, 0x00e2fe02, 0x00e2f6ea, 0x00e2efd2,
0x01c5edd3, 0x00e2f6ea, 0x00717b75, 0x0242, 0x01c6 },
- { 20625000, BANDWIDTH_5_MHZ,
+ { 20625000, 5000000,
0x02376948, 0x011bb4a4, 0x008ddec1, 0x008dda52, 0x008dd5e3,
0x011bb4a4, 0x008dda52, 0x0046ed29, 0x039c, 0x011c }
@@ -153,8 +153,7 @@ struct table {
};
static struct table fe_clockTable[] = {
- {12000000, tab3}, /* FPGA */
- {16384000, tab6}, /* 16.38MHz */
+ {12000000, tab3}, /* 12.00MHz */
{20480000, tab6}, /* 20.48MHz */
{36000000, tab3}, /* 36.00MHz */
{30000000, tab1}, /* 30.00MHz */
@@ -164,7 +163,6 @@ static struct table fe_clockTable[] = {
{34000000, tab2}, /* 34.00MHz */
{24000000, tab1}, /* 24.00MHz */
{22000000, tab8}, /* 22.00MHz */
- {12000000, tab3} /* 12.00MHz */
};
/* fe get */
@@ -203,8 +201,17 @@ fe_modulation_t fe_con[] = {
QAM_64,
};
+enum {
+ PRIORITY_HIGH = 0, /* High-priority stream */
+ PRIORITY_LOW, /* Low-priority stream */
+};
+
/* Standard demodulator functions */
static struct it913xset set_solo_fe[] = {
+ {PRO_LINK, GPIOH5_EN, {0x01}, 0x01},
+ {PRO_LINK, GPIOH5_ON, {0x01}, 0x01},
+ {PRO_LINK, GPIOH5_O, {0x00}, 0x01},
+ {PRO_LINK, GPIOH5_O, {0x01}, 0x01},
{PRO_LINK, DVBT_INTEN, {0x04}, 0x01},
{PRO_LINK, DVBT_ENABLE, {0x05}, 0x01},
{PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01},
@@ -228,13 +235,127 @@ static struct it913xset init_1[] = {
{PRO_LINK, LOCK3_OUT, {0x01}, 0x01},
{PRO_LINK, PADMISCDRSR, {0x01}, 0x01},
{PRO_LINK, PADMISCDR2, {0x00}, 0x01},
+ {PRO_DMOD, 0xec57, {0x00, 0x00}, 0x02},
{PRO_LINK, PADMISCDR4, {0x00}, 0x01}, /* Power up */
{PRO_LINK, PADMISCDR8, {0x00}, 0x01},
{0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
};
-/* ---------IT9137 0x38 tuner init---------- */
-static struct it913xset it9137_set[] = {
+
+/* Version 1 types */
+static struct it913xset it9135_v1[] = {
+ {PRO_DMOD, 0x0051, {0x01}, 0x01},
+ {PRO_DMOD, 0x0070, {0x0a}, 0x01},
+ {PRO_DMOD, 0x007e, {0x04}, 0x01},
+ {PRO_DMOD, 0x0081, {0x0a}, 0x01},
+ {PRO_DMOD, 0x008a, {0x01}, 0x01},
+ {PRO_DMOD, 0x008e, {0x01}, 0x01},
+ {PRO_DMOD, 0x0092, {0x06}, 0x01},
+ {PRO_DMOD, 0x0099, {0x01}, 0x01},
+ {PRO_DMOD, 0x009f, {0xe1}, 0x01},
+ {PRO_DMOD, 0x00a0, {0xcf}, 0x01},
+ {PRO_DMOD, 0x00a3, {0x01}, 0x01},
+ {PRO_DMOD, 0x00a5, {0x01}, 0x01},
+ {PRO_DMOD, 0x00a6, {0x01}, 0x01},
+ {PRO_DMOD, 0x00a9, {0x00}, 0x01},
+ {PRO_DMOD, 0x00aa, {0x01}, 0x01},
+ {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+ {PRO_DMOD, 0x00c2, {0x05}, 0x01},
+ {PRO_DMOD, 0x00c6, {0x19}, 0x01},
+ {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf016, {0x10}, 0x01},
+ {PRO_DMOD, 0xf017, {0x04}, 0x01},
+ {PRO_DMOD, 0xf018, {0x05}, 0x01},
+ {PRO_DMOD, 0xf019, {0x04}, 0x01},
+ {PRO_DMOD, 0xf01a, {0x05}, 0x01},
+ {PRO_DMOD, 0xf021, {0x03}, 0x01},
+ {PRO_DMOD, 0xf022, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf023, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf02b, {0x00}, 0x01},
+ {PRO_DMOD, 0xf02c, {0x01}, 0x01},
+ {PRO_DMOD, 0xf064, {0x03}, 0x01},
+ {PRO_DMOD, 0xf065, {0xf9}, 0x01},
+ {PRO_DMOD, 0xf066, {0x03}, 0x01},
+ {PRO_DMOD, 0xf067, {0x01}, 0x01},
+ {PRO_DMOD, 0xf06f, {0xe0}, 0x01},
+ {PRO_DMOD, 0xf070, {0x03}, 0x01},
+ {PRO_DMOD, 0xf072, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf073, {0x03}, 0x01},
+ {PRO_DMOD, 0xf078, {0x00}, 0x01},
+ {PRO_DMOD, 0xf087, {0x00}, 0x01},
+ {PRO_DMOD, 0xf09b, {0x3f}, 0x01},
+ {PRO_DMOD, 0xf09c, {0x00}, 0x01},
+ {PRO_DMOD, 0xf09d, {0x20}, 0x01},
+ {PRO_DMOD, 0xf09e, {0x00}, 0x01},
+ {PRO_DMOD, 0xf09f, {0x0c}, 0x01},
+ {PRO_DMOD, 0xf0a0, {0x00}, 0x01},
+ {PRO_DMOD, 0xf130, {0x04}, 0x01},
+ {PRO_DMOD, 0xf132, {0x04}, 0x01},
+ {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+ {PRO_DMOD, 0xf146, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+ {PRO_DMOD, 0xf14c, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14d, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+ {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+ {PRO_DMOD, 0xf15a, {0x00}, 0x01},
+ {PRO_DMOD, 0xf15b, {0x08}, 0x01},
+ {PRO_DMOD, 0xf15d, {0x03}, 0x01},
+ {PRO_DMOD, 0xf15e, {0x05}, 0x01},
+ {PRO_DMOD, 0xf163, {0x05}, 0x01},
+ {PRO_DMOD, 0xf166, {0x01}, 0x01},
+ {PRO_DMOD, 0xf167, {0x40}, 0x01},
+ {PRO_DMOD, 0xf168, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf17a, {0x00}, 0x01},
+ {PRO_DMOD, 0xf17b, {0x00}, 0x01},
+ {PRO_DMOD, 0xf183, {0x01}, 0x01},
+ {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+ {PRO_DMOD, 0xf1bc, {0x36}, 0x01},
+ {PRO_DMOD, 0xf1bd, {0x00}, 0x01},
+ {PRO_DMOD, 0xf1cb, {0xa0}, 0x01},
+ {PRO_DMOD, 0xf1cc, {0x01}, 0x01},
+ {PRO_DMOD, 0xf204, {0x10}, 0x01},
+ {PRO_DMOD, 0xf214, {0x00}, 0x01},
+ {PRO_DMOD, 0xf40e, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf40f, {0x40}, 0x01},
+ {PRO_DMOD, 0xf410, {0x08}, 0x01},
+ {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf561, {0x15}, 0x01},
+ {PRO_DMOD, 0xf562, {0x20}, 0x01},
+ {PRO_DMOD, 0xf5df, {0xfb}, 0x01},
+ {PRO_DMOD, 0xf5e0, {0x00}, 0x01},
+ {PRO_DMOD, 0xf5e3, {0x09}, 0x01},
+ {PRO_DMOD, 0xf5e4, {0x01}, 0x01},
+ {PRO_DMOD, 0xf5e5, {0x01}, 0x01},
+ {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+ {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+ {PRO_DMOD, 0xf600, {0x05}, 0x01},
+ {PRO_DMOD, 0xf601, {0x08}, 0x01},
+ {PRO_DMOD, 0xf602, {0x0b}, 0x01},
+ {PRO_DMOD, 0xf603, {0x0e}, 0x01},
+ {PRO_DMOD, 0xf604, {0x11}, 0x01},
+ {PRO_DMOD, 0xf605, {0x14}, 0x01},
+ {PRO_DMOD, 0xf606, {0x17}, 0x01},
+ {PRO_DMOD, 0xf607, {0x1f}, 0x01},
+ {PRO_DMOD, 0xf60e, {0x00}, 0x01},
+ {PRO_DMOD, 0xf60f, {0x04}, 0x01},
+ {PRO_DMOD, 0xf610, {0x32}, 0x01},
+ {PRO_DMOD, 0xf611, {0x10}, 0x01},
+ {PRO_DMOD, 0xf707, {0xfc}, 0x01},
+ {PRO_DMOD, 0xf708, {0x00}, 0x01},
+ {PRO_DMOD, 0xf709, {0x37}, 0x01},
+ {PRO_DMOD, 0xf70a, {0x00}, 0x01},
+ {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+ {PRO_DMOD, 0xf80f, {0x40}, 0x01},
+ {PRO_DMOD, 0xf810, {0x54}, 0x01},
+ {PRO_DMOD, 0xf811, {0x5a}, 0x01},
+ {PRO_DMOD, 0xf905, {0x01}, 0x01},
+ {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+ {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_38[] = {
{PRO_DMOD, 0x0043, {0x00}, 0x01},
{PRO_DMOD, 0x0046, {0x38}, 0x01},
{PRO_DMOD, 0x0051, {0x01}, 0x01},
@@ -244,7 +365,7 @@ static struct it913xset it9137_set[] = {
{PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
{PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
{PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8,
- 0xd0, 0xc3, 0x01 }, 0x0a},
+ 0xd0, 0xc3, 0x01}, 0x0a},
{PRO_DMOD, 0x008e, {0x01}, 0x01},
{PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
{PRO_DMOD, 0x0099, {0x01}, 0x01},
@@ -262,15 +383,25 @@ static struct it913xset it9137_set[] = {
{PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
{PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
{PRO_DMOD, 0x00fc, { 0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77,
- 0x00, 0x02, 0xc8, 0x05, 0x7b }, 0x0c},
+ 0x00, 0x02, 0xc8, 0x05, 0x7b}, 0x0c},
{PRO_DMOD, 0x0109, {0x02}, 0x01},
- {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
- {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0xbc, 0xa0}, 0x04},
+ {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
+ {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0x8a, 0xa0}, 0x04},
{PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03},
{PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
{PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
{PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
- {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8}, 0x04},
+ {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8, 0x59}, 0x05},
+ {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
+ {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
+ {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
+ {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+ {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+ {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+ {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+ {PRO_DMOD, 0xf085, {0x00, 0x02, 0x00}, 0x03},
+ {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
{PRO_DMOD, 0xf130, {0x04}, 0x01},
{PRO_DMOD, 0xf132, {0x04}, 0x01},
{PRO_DMOD, 0xf144, {0x1a}, 0x01},
@@ -301,7 +432,7 @@ static struct it913xset it9137_set[] = {
{PRO_DMOD, 0xf5f8, {0x01}, 0x01},
{PRO_DMOD, 0xf5fd, {0x01}, 0x01},
{PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
- 0x1f }, 0x08},
+ 0x1f}, 0x08},
{PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
{PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
{PRO_DMOD, 0xf78b, {0x01}, 0x01},
@@ -309,21 +440,605 @@ static struct it913xset it9137_set[] = {
{PRO_DMOD, 0xf905, {0x01}, 0x01},
{PRO_DMOD, 0xfb06, {0x03}, 0x01},
{PRO_DMOD, 0xfd8b, {0x00}, 0x01},
- {PRO_LINK, GPIOH5_EN, {0x01}, 0x01},
- {PRO_LINK, GPIOH5_ON, {0x01}, 0x01},
- {PRO_LINK, GPIOH5_O, {0x00}, 0x01},
- {PRO_LINK, GPIOH5_O, {0x01}, 0x01},
- {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+ {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
};
+static struct it913xset it9135_51[] = {
+ {PRO_DMOD, 0x0043, {0x00}, 0x01},
+ {PRO_DMOD, 0x0046, {0x51}, 0x01},
+ {PRO_DMOD, 0x0051, {0x01}, 0x01},
+ {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0x0068, {0x0a}, 0x01},
+ {PRO_DMOD, 0x0070, {0x0a, 0x06, 0x02}, 0x03},
+ {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
+ {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
+ {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc0, 0x96,
+ 0xcf, 0xc3, 0x01}, 0x0a},
+ {PRO_DMOD, 0x008e, {0x01}, 0x01},
+ {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+ {PRO_DMOD, 0x0099, {0x01}, 0x01},
+ {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+ {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+ {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+ {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+ {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+ {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02},
+ {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+ {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
+ {PRO_DMOD, 0x00c4, {0x00}, 0x01},
+ {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+ {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
+ {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
+ {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+ {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x7a, 0x77,
+ 0x01, 0x02, 0xb0, 0x02, 0x7a}, 0x0c},
+ {PRO_DMOD, 0x0109, {0x02}, 0x01},
+ {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
+ {PRO_DMOD, 0x011a, {0xc0, 0x7a, 0xac, 0x8c}, 0x04},
+ {PRO_DMOD, 0x0122, {0x02, 0x70, 0xa4}, 0x03},
+ {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
+ {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+ {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
+ {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc0, 0x59}, 0x05},
+ {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
+ {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
+ {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
+ {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+ {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+ {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+ {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+ {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03},
+ {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+ {PRO_DMOD, 0xf130, {0x04}, 0x01},
+ {PRO_DMOD, 0xf132, {0x04}, 0x01},
+ {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+ {PRO_DMOD, 0xf146, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+ {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+ {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+ {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+ {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+ {PRO_DMOD, 0xf163, {0x05}, 0x01},
+ {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+ {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0xf183, {0x01}, 0x01},
+ {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+ {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+ {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+ {PRO_DMOD, 0xf204, {0x10}, 0x01},
+ {PRO_DMOD, 0xf214, {0x00}, 0x01},
+ {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+ {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+ {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+ {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+ {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+ {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
+ {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+ {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+ {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+ {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+ 0x1f}, 0x08},
+ {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+ {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+ {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+ {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+ {PRO_DMOD, 0xf905, {0x01}, 0x01},
+ {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+ {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_52[] = {
+ {PRO_DMOD, 0x0043, {0x00}, 0x01},
+ {PRO_DMOD, 0x0046, {0x52}, 0x01},
+ {PRO_DMOD, 0x0051, {0x01}, 0x01},
+ {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0x0068, {0x10}, 0x01},
+ {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+ {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xa0, 0x01}, 0x05},
+ {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
+ {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x03, 0x0a, 0x03, 0xb3, 0x97,
+ 0xc0, 0x9e, 0x01}, 0x0a},
+ {PRO_DMOD, 0x008e, {0x01}, 0x01},
+ {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+ {PRO_DMOD, 0x0099, {0x01}, 0x01},
+ {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+ {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+ {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04},
+ {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+ {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+ {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02},
+ {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+ {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
+ {PRO_DMOD, 0x00c4, {0x00}, 0x01},
+ {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+ {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
+ {PRO_DMOD, 0x00f3, {0x05, 0x91, 0x8c}, 0x03},
+ {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+ {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x74, 0x77,
+ 0x02, 0x02, 0xae, 0x02, 0x6e}, 0x0c},
+ {PRO_DMOD, 0x0109, {0x02}, 0x01},
+ {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
+ {PRO_DMOD, 0x011a, {0xcd, 0x62, 0xa4, 0x8c}, 0x04},
+ {PRO_DMOD, 0x0122, {0x03, 0x18, 0x9e}, 0x03},
+ {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
+ {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+ {PRO_DMOD, 0x0137, {0x00, 0x00, 0x07, 0x00, 0x06}, 0x05},
+ {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xb6, 0x59}, 0x05},
+ {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
+ {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
+ {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
+ {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+ {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+ {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+ {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+ {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03},
+ {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+ {PRO_DMOD, 0xf130, {0x04}, 0x01},
+ {PRO_DMOD, 0xf132, {0x04}, 0x01},
+ {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+ {PRO_DMOD, 0xf146, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+ {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+ {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+ {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+ {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+ {PRO_DMOD, 0xf163, {0x05}, 0x01},
+ {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+ {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0xf183, {0x01}, 0x01},
+ {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+ {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+ {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+ {PRO_DMOD, 0xf204, {0x10}, 0x01},
+ {PRO_DMOD, 0xf214, {0x00}, 0x01},
+ {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+ {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+ {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+ {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+ {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+ {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
+ {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+ {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+ {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+ {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+ 0x1f}, 0x08},
+ {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+ {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+ {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+ {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+ {PRO_DMOD, 0xf905, {0x01}, 0x01},
+ {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+ {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+/* Version 2 types */
+static struct it913xset it9135_v2[] = {
+ {PRO_DMOD, 0x0051, {0x01}, 0x01},
+ {PRO_DMOD, 0x0070, {0x0a}, 0x01},
+ {PRO_DMOD, 0x007e, {0x04}, 0x01},
+ {PRO_DMOD, 0x0081, {0x0a}, 0x01},
+ {PRO_DMOD, 0x008a, {0x01}, 0x01},
+ {PRO_DMOD, 0x008e, {0x01}, 0x01},
+ {PRO_DMOD, 0x0092, {0x06}, 0x01},
+ {PRO_DMOD, 0x0099, {0x01}, 0x01},
+ {PRO_DMOD, 0x009f, {0xe1}, 0x01},
+ {PRO_DMOD, 0x00a0, {0xcf}, 0x01},
+ {PRO_DMOD, 0x00a3, {0x01}, 0x01},
+ {PRO_DMOD, 0x00a5, {0x01}, 0x01},
+ {PRO_DMOD, 0x00a6, {0x01}, 0x01},
+ {PRO_DMOD, 0x00a9, {0x00}, 0x01},
+ {PRO_DMOD, 0x00aa, {0x01}, 0x01},
+ {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+ {PRO_DMOD, 0x00c2, {0x05}, 0x01},
+ {PRO_DMOD, 0x00c6, {0x19}, 0x01},
+ {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf02b, {0x00}, 0x01},
+ {PRO_DMOD, 0xf064, {0x03}, 0x01},
+ {PRO_DMOD, 0xf065, {0xf9}, 0x01},
+ {PRO_DMOD, 0xf066, {0x03}, 0x01},
+ {PRO_DMOD, 0xf067, {0x01}, 0x01},
+ {PRO_DMOD, 0xf06f, {0xe0}, 0x01},
+ {PRO_DMOD, 0xf070, {0x03}, 0x01},
+ {PRO_DMOD, 0xf072, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf073, {0x03}, 0x01},
+ {PRO_DMOD, 0xf078, {0x00}, 0x01},
+ {PRO_DMOD, 0xf087, {0x00}, 0x01},
+ {PRO_DMOD, 0xf09b, {0x3f}, 0x01},
+ {PRO_DMOD, 0xf09c, {0x00}, 0x01},
+ {PRO_DMOD, 0xf09d, {0x20}, 0x01},
+ {PRO_DMOD, 0xf09e, {0x00}, 0x01},
+ {PRO_DMOD, 0xf09f, {0x0c}, 0x01},
+ {PRO_DMOD, 0xf0a0, {0x00}, 0x01},
+ {PRO_DMOD, 0xf130, {0x04}, 0x01},
+ {PRO_DMOD, 0xf132, {0x04}, 0x01},
+ {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+ {PRO_DMOD, 0xf146, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+ {PRO_DMOD, 0xf14c, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14d, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+ {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+ {PRO_DMOD, 0xf15a, {0x00}, 0x01},
+ {PRO_DMOD, 0xf15b, {0x08}, 0x01},
+ {PRO_DMOD, 0xf15d, {0x03}, 0x01},
+ {PRO_DMOD, 0xf15e, {0x05}, 0x01},
+ {PRO_DMOD, 0xf163, {0x05}, 0x01},
+ {PRO_DMOD, 0xf166, {0x01}, 0x01},
+ {PRO_DMOD, 0xf167, {0x40}, 0x01},
+ {PRO_DMOD, 0xf168, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf17a, {0x00}, 0x01},
+ {PRO_DMOD, 0xf17b, {0x00}, 0x01},
+ {PRO_DMOD, 0xf183, {0x01}, 0x01},
+ {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+ {PRO_DMOD, 0xf1bc, {0x36}, 0x01},
+ {PRO_DMOD, 0xf1bd, {0x00}, 0x01},
+ {PRO_DMOD, 0xf1cb, {0xa0}, 0x01},
+ {PRO_DMOD, 0xf1cc, {0x01}, 0x01},
+ {PRO_DMOD, 0xf204, {0x10}, 0x01},
+ {PRO_DMOD, 0xf214, {0x00}, 0x01},
+ {PRO_DMOD, 0xf40e, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf40f, {0x40}, 0x01},
+ {PRO_DMOD, 0xf410, {0x08}, 0x01},
+ {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf561, {0x15}, 0x01},
+ {PRO_DMOD, 0xf562, {0x20}, 0x01},
+ {PRO_DMOD, 0xf5e3, {0x09}, 0x01},
+ {PRO_DMOD, 0xf5e4, {0x01}, 0x01},
+ {PRO_DMOD, 0xf5e5, {0x01}, 0x01},
+ {PRO_DMOD, 0xf600, {0x05}, 0x01},
+ {PRO_DMOD, 0xf601, {0x08}, 0x01},
+ {PRO_DMOD, 0xf602, {0x0b}, 0x01},
+ {PRO_DMOD, 0xf603, {0x0e}, 0x01},
+ {PRO_DMOD, 0xf604, {0x11}, 0x01},
+ {PRO_DMOD, 0xf605, {0x14}, 0x01},
+ {PRO_DMOD, 0xf606, {0x17}, 0x01},
+ {PRO_DMOD, 0xf607, {0x1f}, 0x01},
+ {PRO_DMOD, 0xf60e, {0x00}, 0x01},
+ {PRO_DMOD, 0xf60f, {0x04}, 0x01},
+ {PRO_DMOD, 0xf610, {0x32}, 0x01},
+ {PRO_DMOD, 0xf611, {0x10}, 0x01},
+ {PRO_DMOD, 0xf707, {0xfc}, 0x01},
+ {PRO_DMOD, 0xf708, {0x00}, 0x01},
+ {PRO_DMOD, 0xf709, {0x37}, 0x01},
+ {PRO_DMOD, 0xf70a, {0x00}, 0x01},
+ {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+ {PRO_DMOD, 0xf80f, {0x40}, 0x01},
+ {PRO_DMOD, 0xf810, {0x54}, 0x01},
+ {PRO_DMOD, 0xf811, {0x5a}, 0x01},
+ {PRO_DMOD, 0xf905, {0x01}, 0x01},
+ {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+ {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_60[] = {
+ {PRO_DMOD, 0x0043, {0x00}, 0x01},
+ {PRO_DMOD, 0x0046, {0x60}, 0x01},
+ {PRO_DMOD, 0x0051, {0x01}, 0x01},
+ {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0x0068, {0x0a}, 0x01},
+ {PRO_DMOD, 0x006a, {0x03}, 0x01},
+ {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+ {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05},
+ {PRO_DMOD, 0x007e, {0x04}, 0x01},
+ {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
+ {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbe, 0xa0, 0xc6, 0xb6, 0x01}, 0x07},
+ {PRO_DMOD, 0x008e, {0x01}, 0x01},
+ {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+ {PRO_DMOD, 0x0099, {0x01}, 0x01},
+ {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+ {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+ {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+ {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+ {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+ {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
+ {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+ {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
+ {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+ {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
+ {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03},
+ {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+ {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x0a, 0x50, 0x7b, 0x8c,
+ 0x00, 0x02, 0xbe, 0x00}, 0x0b},
+ {PRO_DMOD, 0x0109, {0x02}, 0x01},
+ {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
+ {PRO_DMOD, 0x011a, {0xbe}, 0x01},
+ {PRO_DMOD, 0x0124, {0xae}, 0x01},
+ {PRO_DMOD, 0x0127, {0x00}, 0x01},
+ {PRO_DMOD, 0x012a, {0x56, 0x50, 0x47, 0x42}, 0x04},
+ {PRO_DMOD, 0x0137, {0x00}, 0x01},
+ {PRO_DMOD, 0x013b, {0x08}, 0x01},
+ {PRO_DMOD, 0x013f, {0x5b}, 0x01},
+ {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x19, 0x19, 0x8c, 0x8c, 0x8c,
+ 0x6e, 0x8c, 0x50, 0x8c, 0x8c, 0xac, 0xc6,
+ 0x33}, 0x0f},
+ {PRO_DMOD, 0x0151, {0x28}, 0x01},
+ {PRO_DMOD, 0x0153, {0xbc}, 0x01},
+ {PRO_DMOD, 0x0178, {0x09}, 0x01},
+ {PRO_DMOD, 0x0181, {0x94, 0x6e}, 0x02},
+ {PRO_DMOD, 0x0185, {0x24}, 0x01},
+ {PRO_DMOD, 0x0187, {0x00, 0x00, 0xbe, 0x02, 0x80}, 0x05},
+ {PRO_DMOD, 0xed02, {0xff}, 0x01},
+ {PRO_DMOD, 0xee42, {0xff}, 0x01},
+ {PRO_DMOD, 0xee82, {0xff}, 0x01},
+ {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
+ {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
+ {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+ {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+ {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+ {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+ {PRO_DMOD, 0xf087, {0x00}, 0x01},
+ {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+ {PRO_DMOD, 0xf130, {0x04}, 0x01},
+ {PRO_DMOD, 0xf132, {0x04}, 0x01},
+ {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+ {PRO_DMOD, 0xf146, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+ {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+ {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+ {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+ {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+ {PRO_DMOD, 0xf163, {0x05}, 0x01},
+ {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+ {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0xf183, {0x01}, 0x01},
+ {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+ {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+ {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+ {PRO_DMOD, 0xf204, {0x10}, 0x01},
+ {PRO_DMOD, 0xf214, {0x00}, 0x01},
+ {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+ {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+ {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+ {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+ {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+ {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+ {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17
+ , 0x1f}, 0x08},
+ {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+ {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+ {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+ {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+ {PRO_DMOD, 0xf905, {0x01}, 0x01},
+ {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+ {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_61[] = {
+ {PRO_DMOD, 0x0043, {0x00}, 0x01},
+ {PRO_DMOD, 0x0046, {0x61}, 0x01},
+ {PRO_DMOD, 0x0051, {0x01}, 0x01},
+ {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0x0068, {0x06}, 0x01},
+ {PRO_DMOD, 0x006a, {0x03}, 0x01},
+ {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+ {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x90, 0x01}, 0x05},
+ {PRO_DMOD, 0x007e, {0x04}, 0x01},
+ {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
+ {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbc, 0x9c, 0xcc, 0xa8, 0x01}, 0x07},
+ {PRO_DMOD, 0x008e, {0x01}, 0x01},
+ {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+ {PRO_DMOD, 0x0099, {0x01}, 0x01},
+ {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+ {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+ {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04},
+ {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+ {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+ {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
+ {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+ {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
+ {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+ {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
+ {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03},
+ {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+ {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x08, 0x50, 0x7b, 0x8c,
+ 0x01, 0x02, 0xc8, 0x00}, 0x0b},
+ {PRO_DMOD, 0x0109, {0x02}, 0x01},
+ {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
+ {PRO_DMOD, 0x011a, {0xc6}, 0x01},
+ {PRO_DMOD, 0x0124, {0xa8}, 0x01},
+ {PRO_DMOD, 0x0127, {0x00}, 0x01},
+ {PRO_DMOD, 0x012a, {0x59, 0x50, 0x47, 0x42}, 0x04},
+ {PRO_DMOD, 0x0137, {0x00}, 0x01},
+ {PRO_DMOD, 0x013b, {0x05}, 0x01},
+ {PRO_DMOD, 0x013f, {0x5b}, 0x01},
+ {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x59, 0x8c, 0x8c, 0x8c,
+ 0x7b, 0x8c, 0x50, 0x8c, 0x8c, 0xa8, 0xc6,
+ 0x33}, 0x0f},
+ {PRO_DMOD, 0x0151, {0x28}, 0x01},
+ {PRO_DMOD, 0x0153, {0xcc}, 0x01},
+ {PRO_DMOD, 0x0178, {0x09}, 0x01},
+ {PRO_DMOD, 0x0181, {0x9c, 0x76}, 0x02},
+ {PRO_DMOD, 0x0185, {0x28}, 0x01},
+ {PRO_DMOD, 0x0187, {0x01, 0x00, 0xaa, 0x02, 0x80}, 0x05},
+ {PRO_DMOD, 0xed02, {0xff}, 0x01},
+ {PRO_DMOD, 0xee42, {0xff}, 0x01},
+ {PRO_DMOD, 0xee82, {0xff}, 0x01},
+ {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
+ {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
+ {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+ {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+ {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+ {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+ {PRO_DMOD, 0xf087, {0x00}, 0x01},
+ {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+ {PRO_DMOD, 0xf130, {0x04}, 0x01},
+ {PRO_DMOD, 0xf132, {0x04}, 0x01},
+ {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+ {PRO_DMOD, 0xf146, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+ {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+ {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+ {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+ {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+ {PRO_DMOD, 0xf163, {0x05}, 0x01},
+ {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+ {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0xf183, {0x01}, 0x01},
+ {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+ {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+ {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+ {PRO_DMOD, 0xf204, {0x10}, 0x01},
+ {PRO_DMOD, 0xf214, {0x00}, 0x01},
+ {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+ {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+ {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+ {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+ {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+ {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+ {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+ 0x1f}, 0x08},
+ {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+ {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+ {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+ {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+ {PRO_DMOD, 0xf905, {0x01}, 0x01},
+ {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+ {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_62[] = {
+ {PRO_DMOD, 0x0043, {0x00}, 0x01},
+ {PRO_DMOD, 0x0046, {0x62}, 0x01},
+ {PRO_DMOD, 0x0051, {0x01}, 0x01},
+ {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0x0068, {0x0a}, 0x01},
+ {PRO_DMOD, 0x006a, {0x03}, 0x01},
+ {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+ {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05},
+ {PRO_DMOD, 0x007e, {0x04}, 0x01},
+ {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
+ {PRO_DMOD, 0x0084, { 0x0a, 0x33, 0xb8, 0x9c, 0xb2, 0xa6, 0x01},
+ 0x07},
+ {PRO_DMOD, 0x008e, {0x01}, 0x01},
+ {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+ {PRO_DMOD, 0x0099, {0x01}, 0x01},
+ {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+ {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+ {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+ {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+ {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+ {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
+ {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+ {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
+ {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+ {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
+ {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
+ {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+ {PRO_DMOD, 0x00fc, { 0x02, 0x03, 0x02, 0x09, 0x50, 0x6e, 0x8c,
+ 0x02, 0x02, 0xc2, 0x00}, 0x0b},
+ {PRO_DMOD, 0x0109, {0x02}, 0x01},
+ {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
+ {PRO_DMOD, 0x011a, {0xb8}, 0x01},
+ {PRO_DMOD, 0x0124, {0xa8}, 0x01},
+ {PRO_DMOD, 0x0127, {0x00}, 0x01},
+ {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+ {PRO_DMOD, 0x0137, {0x00}, 0x01},
+ {PRO_DMOD, 0x013b, {0x05}, 0x01},
+ {PRO_DMOD, 0x013f, {0x5b}, 0x01},
+ {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x19, 0x8c, 0x8c, 0x8c,
+ 0x7b, 0x8c, 0x50, 0x70, 0x8c, 0x96, 0xd0,
+ 0x33}, 0x0f},
+ {PRO_DMOD, 0x0151, {0x28}, 0x01},
+ {PRO_DMOD, 0x0153, {0xb2}, 0x01},
+ {PRO_DMOD, 0x0178, {0x09}, 0x01},
+ {PRO_DMOD, 0x0181, {0x9c, 0x6e}, 0x02},
+ {PRO_DMOD, 0x0185, {0x24}, 0x01},
+ {PRO_DMOD, 0x0187, {0x00, 0x00, 0xb8, 0x02, 0x80}, 0x05},
+ {PRO_DMOD, 0xed02, {0xff}, 0x01},
+ {PRO_DMOD, 0xee42, {0xff}, 0x01},
+ {PRO_DMOD, 0xee82, {0xff}, 0x01},
+ {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+ {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
+ {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
+ {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+ {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+ {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+ {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+ {PRO_DMOD, 0xf087, {0x00}, 0x01},
+ {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+ {PRO_DMOD, 0xf130, {0x04}, 0x01},
+ {PRO_DMOD, 0xf132, {0x04}, 0x01},
+ {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+ {PRO_DMOD, 0xf146, {0x00}, 0x01},
+ {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+ {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+ {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+ {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+ {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+ {PRO_DMOD, 0xf163, {0x05}, 0x01},
+ {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+ {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+ {PRO_DMOD, 0xf183, {0x01}, 0x01},
+ {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+ {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+ {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+ {PRO_DMOD, 0xf204, {0x10}, 0x01},
+ {PRO_DMOD, 0xf214, {0x00}, 0x01},
+ {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+ {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+ {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+ {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+ {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+ {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+ {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+ {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+ 0x1f}, 0x08},
+ {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+ {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+ {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+ {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+ {PRO_DMOD, 0xf905, {0x01}, 0x01},
+ {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+ {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+/* Tuner setting scripts (still keeping it9137) */
static struct it913xset it9137_tuner_off[] = {
{PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */
{PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */
{PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04},
+ {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}, 0x0c},
+ {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04},
+ {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00}, 0x09},
+ {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00}, 0x0a},
+ {PRO_DMOD, 0xec20, {0x00}, 0x01},
{PRO_DMOD, 0xec3f, {0x01}, 0x01},
{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
};
+static struct it913xset set_it9135_template[] = {
+ {PRO_DMOD, 0xee06, {0x00}, 0x01},
+ {PRO_DMOD, 0xec56, {0x00}, 0x01},
+ {PRO_DMOD, 0xec4c, {0x00}, 0x01},
+ {PRO_DMOD, 0xec4d, {0x00}, 0x01},
+ {PRO_DMOD, 0xec4e, {0x00}, 0x01},
+ {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */
+ {PRO_DMOD, 0x011f, {0x00}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
static struct it913xset set_it9137_template[] = {
{PRO_DMOD, 0xee06, {0x00}, 0x01},
{PRO_DMOD, 0xec56, {0x00}, 0x01},
diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c
index d4bd24eb4700..84df03c29179 100644
--- a/drivers/media/dvb/frontends/it913x-fe.c
+++ b/drivers/media/dvb/frontends/it913x-fe.c
@@ -46,13 +46,18 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
dprintk(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
*p, *(p+1), *(p+2), *(p+3), *(p+4), \
*(p+5), *(p+6), *(p+7));
+#define info(format, arg...) \
+ printk(KERN_INFO "it913x-fe: " format "\n" , ## arg)
struct it913x_fe_state {
struct dvb_frontend frontend;
struct i2c_adapter *i2c_adap;
+ struct ite_config *config;
u8 i2c_addr;
u32 frequency;
- u8 adf;
+ fe_modulation_t constellation;
+ fe_transmit_mode_t transmission_mode;
+ u8 priority;
u32 crystalFrequency;
u32 adcFrequency;
u8 tuner_type;
@@ -62,6 +67,7 @@ struct it913x_fe_state {
u8 tun_fdiv;
u8 tun_clk_mode;
u32 tun_fn_min;
+ u32 ucblocks;
};
static int it913x_read_reg(struct it913x_fe_state *state,
@@ -211,20 +217,24 @@ static int it913x_init_tuner(struct it913x_fe_state *state)
state->tun_fn_min /= (state->tun_fdiv * nv_val);
deb_info("Tuner fn_min %d", state->tun_fn_min);
- for (i = 0; i < 50; i++) {
- reg = it913x_read_reg_u8(state, 0xec82);
- if (reg > 0)
- break;
- if (reg < 0)
- return -ENODEV;
- udelay(2000);
+ if (state->config->chip_ver > 1)
+ msleep(50);
+ else {
+ for (i = 0; i < 50; i++) {
+ reg = it913x_read_reg_u8(state, 0xec82);
+ if (reg > 0)
+ break;
+ if (reg < 0)
+ return -ENODEV;
+ udelay(2000);
+ }
}
return it913x_write_reg(state, PRO_DMOD, 0xed81, val);
}
static int it9137_set_tuner(struct it913x_fe_state *state,
- enum fe_bandwidth bandwidth, u32 frequency_m)
+ u32 bandwidth, u32 frequency_m)
{
struct it913xset *set_tuner = set_it9137_template;
int ret, reg;
@@ -237,6 +247,11 @@ static int it9137_set_tuner(struct it913x_fe_state *state,
u8 lna_band;
u8 bw;
+ if (state->config->firmware_ver == 1)
+ set_tuner = set_it9135_template;
+ else
+ set_tuner = set_it9137_template;
+
deb_info("Tuner Frequency %d Bandwidth %d", frequency, bandwidth);
if (frequency >= 51000 && frequency <= 440000) {
@@ -273,16 +288,21 @@ static int it9137_set_tuner(struct it913x_fe_state *state,
return -EINVAL;
set_tuner[0].reg[0] = lna_band;
- if (bandwidth == BANDWIDTH_5_MHZ)
+ switch (bandwidth) {
+ case 5000000:
bw = 0;
- else if (bandwidth == BANDWIDTH_6_MHZ)
+ break;
+ case 6000000:
bw = 2;
- else if (bandwidth == BANDWIDTH_7_MHZ)
+ break;
+ case 7000000:
bw = 4;
- else if (bandwidth == BANDWIDTH_8_MHZ)
- bw = 6;
- else
+ break;
+ default:
+ case 8000000:
bw = 6;
+ break;
+ }
set_tuner[1].reg[0] = bw;
set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
@@ -361,7 +381,7 @@ static int it9137_set_tuner(struct it913x_fe_state *state,
}
static int it913x_fe_select_bw(struct it913x_fe_state *state,
- enum fe_bandwidth bandwidth, u32 adcFrequency)
+ u32 bandwidth, u32 adcFrequency)
{
int ret, i;
u8 buffer[256];
@@ -374,17 +394,21 @@ static int it913x_fe_select_bw(struct it913x_fe_state *state,
deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency);
- if (bandwidth == BANDWIDTH_5_MHZ)
+ switch (bandwidth) {
+ case 5000000:
bw = 3;
- else if (bandwidth == BANDWIDTH_6_MHZ)
+ break;
+ case 6000000:
bw = 0;
- else if (bandwidth == BANDWIDTH_7_MHZ)
+ break;
+ case 7000000:
bw = 1;
- else if (bandwidth == BANDWIDTH_8_MHZ)
- bw = 2;
- else
+ break;
+ default:
+ case 8000000:
bw = 2;
-
+ break;
+ }
ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw);
if (state->table == NULL)
@@ -477,46 +501,162 @@ static int it913x_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
return 0;
}
+/* FEC values based on fe_code_rate_t non supported values 0*/
+int it913x_qpsk_pval[] = {0, -93, -91, -90, 0, -89, -88};
+int it913x_16qam_pval[] = {0, -87, -85, -84, 0, -83, -82};
+int it913x_64qam_pval[] = {0, -82, -80, -78, 0, -77, -76};
+
+static int it913x_get_signal_strength(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ u8 code_rate;
+ int ret, temp;
+ u8 lna_gain_os;
+
+ ret = it913x_read_reg_u8(state, VAR_P_INBAND);
+ if (ret < 0)
+ return ret;
+
+ /* VHF/UHF gain offset */
+ if (state->frequency < 300000000)
+ lna_gain_os = 7;
+ else
+ lna_gain_os = 14;
+
+ temp = (ret - 100) - lna_gain_os;
+
+ if (state->priority == PRIORITY_HIGH)
+ code_rate = p->code_rate_HP;
+ else
+ code_rate = p->code_rate_LP;
+
+ if (code_rate >= ARRAY_SIZE(it913x_qpsk_pval))
+ return -EINVAL;
+
+ deb_info("Reg VAR_P_INBAND:%d Calc Offset Value:%d", ret, temp);
+
+ /* Apply FEC offset values*/
+ switch (p->modulation) {
+ case QPSK:
+ temp -= it913x_qpsk_pval[code_rate];
+ break;
+ case QAM_16:
+ temp -= it913x_16qam_pval[code_rate];
+ break;
+ case QAM_64:
+ temp -= it913x_64qam_pval[code_rate];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (temp < -15)
+ ret = 0;
+ else if ((-15 <= temp) && (temp < 0))
+ ret = (2 * (temp + 15)) / 3;
+ else if ((0 <= temp) && (temp < 20))
+ ret = 4 * temp + 10;
+ else if ((20 <= temp) && (temp < 35))
+ ret = (2 * (temp - 20)) / 3 + 90;
+ else if (temp >= 35)
+ ret = 100;
+
+ deb_info("Signal Strength :%d", ret);
+
+ return ret;
+}
+
static int it913x_fe_read_signal_strength(struct dvb_frontend *fe,
u16 *strength)
{
struct it913x_fe_state *state = fe->demodulator_priv;
- int ret = it913x_read_reg_u8(state, SIGNAL_LEVEL);
- /*SIGNAL_LEVEL always returns 100%! so using FE_HAS_SIGNAL as switch*/
- if (state->it913x_status & FE_HAS_SIGNAL)
- ret = (ret * 0xff) / 0x64;
- else
- ret = 0x0;
- ret |= ret << 0x8;
- *strength = ret;
- return 0;
+ int ret = 0;
+ if (state->config->read_slevel) {
+ if (state->it913x_status & FE_HAS_SIGNAL)
+ ret = it913x_read_reg_u8(state, SIGNAL_LEVEL);
+ } else
+ ret = it913x_get_signal_strength(fe);
+
+ if (ret >= 0)
+ *strength = (u16)((u32)ret * 0xffff / 0x64);
+
+ return (ret < 0) ? -ENODEV : 0;
}
-static int it913x_fe_read_snr(struct dvb_frontend *fe, u16* snr)
+static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct it913x_fe_state *state = fe->demodulator_priv;
- int ret = it913x_read_reg_u8(state, SIGNAL_QUALITY);
- ret = (ret * 0xff) / 0x64;
- ret |= (ret << 0x8);
- *snr = ~ret;
- return 0;
+ int ret;
+ u8 reg[3];
+ u32 snr_val, snr_min, snr_max;
+ u32 temp;
+
+ ret = it913x_read_reg(state, 0x2c, reg, sizeof(reg));
+
+ snr_val = (u32)(reg[2] << 16) | (reg[1] << 8) | reg[0];
+
+ ret |= it913x_read_reg(state, 0xf78b, reg, 1);
+ if (reg[0])
+ snr_val /= reg[0];
+
+ if (state->transmission_mode == TRANSMISSION_MODE_2K)
+ snr_val *= 4;
+ else if (state->transmission_mode == TRANSMISSION_MODE_4K)
+ snr_val *= 2;
+
+ if (state->constellation == QPSK) {
+ snr_min = 0xb4711;
+ snr_max = 0x191451;
+ } else if (state->constellation == QAM_16) {
+ snr_min = 0x4f0d5;
+ snr_max = 0xc7925;
+ } else if (state->constellation == QAM_64) {
+ snr_min = 0x256d0;
+ snr_max = 0x626be;
+ } else
+ return -EINVAL;
+
+ if (snr_val < snr_min)
+ *snr = 0;
+ else if (snr_val < snr_max) {
+ temp = (snr_val - snr_min) >> 5;
+ temp *= 0xffff;
+ temp /= (snr_max - snr_min) >> 5;
+ *snr = (u16)temp;
+ } else
+ *snr = 0xffff;
+
+ return (ret < 0) ? -ENODEV : 0;
}
static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
{
- *ber = 0;
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 reg[5];
+ /* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */
+ ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
+ state->ucblocks += (u32)(reg[1] << 8) | reg[0];
+ *ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2];
return 0;
}
static int it913x_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
- *ucblocks = 0;
- return 0;
+ struct it913x_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 reg[2];
+ /* Aborted Packets */
+ ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
+ state->ucblocks += (u32)(reg[1] << 8) | reg[0];
+ *ucblocks = state->ucblocks;
+ return ret;
}
-static int it913x_fe_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int it913x_fe_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct it913x_fe_state *state = fe->demodulator_priv;
int ret;
u8 reg[8];
@@ -524,26 +664,32 @@ static int it913x_fe_get_frontend(struct dvb_frontend *fe,
ret = it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
if (reg[3] < 3)
- p->u.ofdm.constellation = fe_con[reg[3]];
+ p->modulation = fe_con[reg[3]];
if (reg[0] < 3)
- p->u.ofdm.transmission_mode = fe_mode[reg[0]];
+ p->transmission_mode = fe_mode[reg[0]];
if (reg[1] < 4)
- p->u.ofdm.guard_interval = fe_gi[reg[1]];
+ p->guard_interval = fe_gi[reg[1]];
if (reg[2] < 4)
- p->u.ofdm.hierarchy_information = fe_hi[reg[2]];
+ p->hierarchy = fe_hi[reg[2]];
+
+ state->priority = reg[5];
- p->u.ofdm.code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE;
- p->u.ofdm.code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE;
+ p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE;
+ p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE;
+
+ /* Update internal state to reflect the autodetected props */
+ state->constellation = p->modulation;
+ state->transmission_mode = p->transmission_mode;
return 0;
}
-static int it913x_fe_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int it913x_fe_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct it913x_fe_state *state = fe->demodulator_priv;
int ret, i;
u8 empty_ch, last_ch;
@@ -551,7 +697,7 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe,
state->it913x_status = 0;
/* Set bw*/
- ret = it913x_fe_select_bw(state, p->u.ofdm.bandwidth,
+ ret = it913x_fe_select_bw(state, p->bandwidth_hz,
state->adcFrequency);
/* Training Mode Off */
@@ -571,20 +717,25 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe,
i = 1;
else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000))
i = 2;
- else
- return -EOPNOTSUPP;
+ else
+ return -EOPNOTSUPP;
ret = it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
deb_info("Frontend Set Tuner Type %02x", state->tuner_type);
switch (state->tuner_type) {
- case IT9137: /* Tuner type 0x38 */
+ case IT9135_38:
+ case IT9135_51:
+ case IT9135_52:
+ case IT9135_60:
+ case IT9135_61:
+ case IT9135_62:
ret = it9137_set_tuner(state,
- p->u.ofdm.bandwidth, p->frequency);
+ p->bandwidth_hz, p->frequency);
break;
default:
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -678,16 +829,19 @@ static u32 compute_div(u32 a, u32 b, u32 x)
static int it913x_fe_start(struct it913x_fe_state *state)
{
- struct it913xset *set_fe;
+ struct it913xset *set_lna;
struct it913xset *set_mode;
int ret;
- u8 adf = (state->adf & 0xf);
+ u8 adf = (state->config->adf & 0xf);
u32 adc, xtal;
u8 b[4];
- ret = it913x_init_tuner(state);
+ if (state->config->chip_ver == 1)
+ ret = it913x_init_tuner(state);
+
+ info("ADF table value :%02x", adf);
- if (adf < 12) {
+ if (adf < 10) {
state->crystalFrequency = fe_clockTable[adf].xtal ;
state->table = fe_clockTable[adf].table;
state->adcFrequency = state->table->adcFrequency;
@@ -698,9 +852,6 @@ static int it913x_fe_start(struct it913x_fe_state *state)
} else
return -EINVAL;
- deb_info("Xtal Freq :%d Adc Freq :%d Adc %08x Xtal %08x",
- state->crystalFrequency, state->adcFrequency, adc, xtal);
-
/* Set LED indicator on GPIOH3 */
ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1);
ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1);
@@ -721,22 +872,71 @@ static int it913x_fe_start(struct it913x_fe_state *state)
b[2] = (adc >> 16) & 0xff;
ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3);
+ if (state->config->adc_x2)
+ ret |= it913x_write_reg(state, PRO_DMOD, ADC_X_2, 0x01);
+ b[0] = 0;
+ b[1] = 0;
+ b[2] = 0;
+ ret |= it913x_write(state, PRO_DMOD, 0x0029, b, 3);
+
+ info("Crystal Frequency :%d Adc Frequency :%d ADC X2: %02x",
+ state->crystalFrequency, state->adcFrequency,
+ state->config->adc_x2);
+ deb_info("Xtal value :%04x Adc value :%04x", xtal, adc);
+
+ if (ret < 0)
+ return -ENODEV;
+
+ /* v1 or v2 tuner script */
+ if (state->config->chip_ver > 1)
+ ret = it913x_fe_script_loader(state, it9135_v2);
+ else
+ ret = it913x_fe_script_loader(state, it9135_v1);
+ if (ret < 0)
+ return ret;
+
+ /* LNA Scripts */
switch (state->tuner_type) {
- case IT9137: /* Tuner type 0x38 */
- set_fe = it9137_set;
+ case IT9135_51:
+ set_lna = it9135_51;
+ break;
+ case IT9135_52:
+ set_lna = it9135_52;
+ break;
+ case IT9135_60:
+ set_lna = it9135_60;
+ break;
+ case IT9135_61:
+ set_lna = it9135_61;
break;
+ case IT9135_62:
+ set_lna = it9135_62;
+ break;
+ case IT9135_38:
default:
- return -EINVAL;
+ set_lna = it9135_38;
+ }
+ info("Tuner LNA type :%02x", state->tuner_type);
+
+ ret = it913x_fe_script_loader(state, set_lna);
+ if (ret < 0)
+ return ret;
+
+ if (state->config->chip_ver == 2) {
+ ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1);
+ ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0);
+ ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0);
+ ret |= it913x_init_tuner(state);
}
+ if (ret < 0)
+ return -ENODEV;
- /* set the demod */
- ret = it913x_fe_script_loader(state, set_fe);
/* Always solo frontend */
set_mode = set_solo_fe;
ret |= it913x_fe_script_loader(state, set_mode);
ret |= it913x_fe_suspend(state);
- return 0;
+ return (ret < 0) ? -ENODEV : 0;
}
static int it913x_fe_init(struct dvb_frontend *fe)
@@ -746,17 +946,11 @@ static int it913x_fe_init(struct dvb_frontend *fe)
/* Power Up Tuner - common all versions */
ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1);
- ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0);
-
ret |= it913x_fe_script_loader(state, init_1);
- switch (state->tuner_type) {
- case IT9137:
- ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0);
- break;
- default:
- return -EINVAL;
- }
+ ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0);
+
+ ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0);
return (ret < 0) ? -ENODEV : 0;
}
@@ -770,19 +964,34 @@ static void it913x_fe_release(struct dvb_frontend *fe)
static struct dvb_frontend_ops it913x_fe_ofdm_ops;
struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
- u8 i2c_addr, u8 adf, u8 type)
+ u8 i2c_addr, struct ite_config *config)
{
struct it913x_fe_state *state = NULL;
int ret;
+
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL);
if (state == NULL)
+ return NULL;
+ if (config == NULL)
goto error;
state->i2c_adap = i2c_adap;
state->i2c_addr = i2c_addr;
- state->adf = adf;
- state->tuner_type = type;
+ state->config = config;
+
+ switch (state->config->tuner_id_0) {
+ case IT9135_51:
+ case IT9135_52:
+ case IT9135_60:
+ case IT9135_61:
+ case IT9135_62:
+ state->tuner_type = state->config->tuner_id_0;
+ break;
+ default:
+ case IT9135_38:
+ state->tuner_type = IT9135_38;
+ }
ret = it913x_fe_start(state);
if (ret < 0)
@@ -802,10 +1011,9 @@ error:
EXPORT_SYMBOL(it913x_fe_attach);
static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "it913x-fe DVB-T",
- .type = FE_OFDM,
.frequency_min = 51000000,
.frequency_max = 1680000000,
.frequency_stepsize = 62500,
@@ -835,5 +1043,5 @@ static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
MODULE_DESCRIPTION("it913x Frontend and it9137 tuner");
MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
-MODULE_VERSION("1.07");
+MODULE_VERSION("1.15");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/it913x-fe.h b/drivers/media/dvb/frontends/it913x-fe.h
index 9d97f32e690b..07fa4594c12b 100644
--- a/drivers/media/dvb/frontends/it913x-fe.h
+++ b/drivers/media/dvb/frontends/it913x-fe.h
@@ -23,13 +23,29 @@
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
+
+struct ite_config {
+ u8 chip_ver;
+ u16 chip_type;
+ u32 firmware;
+ u8 firmware_ver;
+ u8 adc_x2;
+ u8 tuner_id_0;
+ u8 tuner_id_1;
+ u8 dual_mode;
+ u8 adf;
+ /* option to read SIGNAL_LEVEL */
+ u8 read_slevel;
+};
+
#if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \
defined(MODULE))
extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
- u8 i2c_addr, u8 adf, u8 type);
+ u8 i2c_addr, struct ite_config *config);
#else
static inline struct dvb_frontend *it913x_fe_attach(
- struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 adf, u8 type)
+ struct i2c_adapter *i2c_adap,
+ u8 i2c_addr, struct ite_config *config)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
@@ -134,6 +150,16 @@ static inline struct dvb_frontend *it913x_fe_attach(
#define COEFF_1_2048 0x0001
#define XTAL_CLK 0x0025
#define BFS_FCW 0x0029
+
+/* Error Regs */
+#define RSD_ABORT_PKT_LSB 0x0032
+#define RSD_ABORT_PKT_MSB 0x0033
+#define RSD_BIT_ERR_0_7 0x0034
+#define RSD_BIT_ERR_8_15 0x0035
+#define RSD_BIT_ERR_23_16 0x0036
+#define RSD_BIT_COUNT_LSB 0x0037
+#define RSD_BIT_COUNT_MSB 0x0038
+
#define TPSD_LOCK 0x003c
#define TRAINING_MODE 0x0040
#define ADC_X_2 0x0045
@@ -144,8 +170,16 @@ static inline struct dvb_frontend *it913x_fe_attach(
#define EST_SIGNAL_LEVEL 0x004a
#define FREE_BAND 0x004b
#define SUSPEND_FLAG 0x004c
-/* Build in tuners */
+#define VAR_P_INBAND 0x00f7
+
+/* Build in tuner types */
#define IT9137 0x38
+#define IT9135_38 0x38
+#define IT9135_51 0x51
+#define IT9135_52 0x52
+#define IT9135_60 0x60
+#define IT9135_61 0x61
+#define IT9135_62 0x62
enum {
CMD_DEMOD_READ = 0,
@@ -193,4 +227,11 @@ enum {
WRITE_CMD,
};
+enum {
+ IT9135_AUTO = 0,
+ IT9137_FW,
+ IT9135_V1_FW,
+ IT9135_V2_FW,
+};
+
#endif /* IT913X_FE_H */
diff --git a/drivers/media/dvb/frontends/itd1000.c b/drivers/media/dvb/frontends/itd1000.c
index aa9ccb821fa5..316457584fe7 100644
--- a/drivers/media/dvb/frontends/itd1000.c
+++ b/drivers/media/dvb/frontends/itd1000.c
@@ -250,13 +250,14 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz)
itd1000_set_vco(state, freq_khz);
}
-static int itd1000_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int itd1000_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct itd1000_state *state = fe->tuner_priv;
u8 pllcon1;
- itd1000_set_lo(state, p->frequency);
- itd1000_set_lpf_bw(state, p->u.qpsk.symbol_rate);
+ itd1000_set_lo(state, c->frequency);
+ itd1000_set_lpf_bw(state, c->symbol_rate);
pllcon1 = itd1000_read_reg(state, PLLCON1) & 0x7f;
itd1000_write_reg(state, PLLCON1, pllcon1 | (1 << 7));
diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c
index 9a517a4bf96d..bc5a82082aaa 100644
--- a/drivers/media/dvb/frontends/ix2505v.c
+++ b/drivers/media/dvb/frontends/ix2505v.c
@@ -129,12 +129,12 @@ static int ix2505v_release(struct dvb_frontend *fe)
* 1 -> 8 -> 6
*/
-static int ix2505v_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int ix2505v_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct ix2505v_state *state = fe->tuner_priv;
- u32 frequency = params->frequency;
- u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000;
+ u32 frequency = c->frequency;
+ u32 b_w = (c->symbol_rate * 27) / 32000;
u32 div_factor, N , A, x;
int ret = 0, len;
u8 gain, cc, ref, psc, local_osc, lpf;
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 445fa1068064..36fcf559e361 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -117,18 +117,17 @@ static int reset_and_configure (struct l64781_state* state)
return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV;
}
-static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
+static int apply_frontend_param(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct l64781_state* state = fe->demodulator_priv;
/* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };
/* QPSK, QAM_16, QAM_64 */
static const u8 qam_tab [] = { 2, 4, 0, 6 };
- static const u8 bw_tab [] = { 8, 7, 6 }; /* 8Mhz, 7MHz, 6MHz */
static const u8 guard_tab [] = { 1, 2, 4, 8 };
/* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */
static const u32 ppm = 8000;
- struct dvb_ofdm_parameters *p = &param->u.ofdm;
u32 ddfs_offset_fixed;
/* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */
/* bw_tab[p->bandWidth]<<10)/15625; */
@@ -137,18 +136,29 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
u8 val0x04;
u8 val0x05;
u8 val0x06;
- int bw = p->bandwidth - BANDWIDTH_8_MHZ;
+ int bw;
+
+ switch (p->bandwidth_hz) {
+ case 8000000:
+ bw = 8;
+ break;
+ case 7000000:
+ bw = 7;
+ break;
+ case 6000000:
+ bw = 6;
+ break;
+ default:
+ return -EINVAL;
+ }
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, param);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- if (param->inversion != INVERSION_ON &&
- param->inversion != INVERSION_OFF)
- return -EINVAL;
-
- if (bw < 0 || bw > 2)
+ if (p->inversion != INVERSION_ON &&
+ p->inversion != INVERSION_OFF)
return -EINVAL;
if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 &&
@@ -156,14 +166,14 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
p->code_rate_HP != FEC_7_8)
return -EINVAL;
- if (p->hierarchy_information != HIERARCHY_NONE &&
+ if (p->hierarchy != HIERARCHY_NONE &&
(p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 &&
p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 &&
p->code_rate_LP != FEC_7_8))
return -EINVAL;
- if (p->constellation != QPSK && p->constellation != QAM_16 &&
- p->constellation != QAM_64)
+ if (p->modulation != QPSK && p->modulation != QAM_16 &&
+ p->modulation != QAM_64)
return -EINVAL;
if (p->transmission_mode != TRANSMISSION_MODE_2K &&
@@ -174,22 +184,22 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
p->guard_interval > GUARD_INTERVAL_1_4)
return -EINVAL;
- if (p->hierarchy_information < HIERARCHY_NONE ||
- p->hierarchy_information > HIERARCHY_4)
+ if (p->hierarchy < HIERARCHY_NONE ||
+ p->hierarchy > HIERARCHY_4)
return -EINVAL;
- ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000;
+ ddfs_offset_fixed = 0x4000-(ppm<<16)/bw/1000000;
/* This works up to 20000 ppm, it overflows if too large ppm! */
init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) /
- bw_tab[p->bandwidth] & 0xFFFFFF);
+ bw & 0xFFFFFF);
/* SPI bias calculation is slightly modified to fit in 32bit */
/* will work for high ppm only... */
spi_bias = 378 * (1 << 10);
spi_bias *= 16;
- spi_bias *= bw_tab[p->bandwidth];
- spi_bias *= qam_tab[p->constellation];
+ spi_bias *= bw;
+ spi_bias *= qam_tab[p->modulation];
spi_bias /= p->code_rate_HP + 1;
spi_bias /= (guard_tab[p->guard_interval] + 32);
spi_bias *= 1000;
@@ -199,10 +209,10 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
val0x04 = (p->transmission_mode << 2) | p->guard_interval;
val0x05 = fec_tab[p->code_rate_HP];
- if (p->hierarchy_information != HIERARCHY_NONE)
+ if (p->hierarchy != HIERARCHY_NONE)
val0x05 |= (p->code_rate_LP - FEC_1_2) << 3;
- val0x06 = (p->hierarchy_information << 2) | p->constellation;
+ val0x06 = (p->hierarchy << 2) | p->modulation;
l64781_writereg (state, 0x04, val0x04);
l64781_writereg (state, 0x05, val0x05);
@@ -220,7 +230,7 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
l64781_writereg (state, 0x1b, spi_bias & 0xff);
l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff);
l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) |
- (param->inversion == INVERSION_ON ? 0x80 : 0x00));
+ (p->inversion == INVERSION_ON ? 0x80 : 0x00));
l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff);
l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f);
@@ -233,8 +243,9 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
return 0;
}
-static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param)
+static int get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct l64781_state* state = fe->demodulator_priv;
int tmp;
@@ -242,98 +253,95 @@ static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters*
tmp = l64781_readreg(state, 0x04);
switch(tmp & 3) {
case 0:
- param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ p->guard_interval = GUARD_INTERVAL_1_32;
break;
case 1:
- param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+ p->guard_interval = GUARD_INTERVAL_1_16;
break;
case 2:
- param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+ p->guard_interval = GUARD_INTERVAL_1_8;
break;
case 3:
- param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+ p->guard_interval = GUARD_INTERVAL_1_4;
break;
}
switch((tmp >> 2) & 3) {
case 0:
- param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+ p->transmission_mode = TRANSMISSION_MODE_2K;
break;
case 1:
- param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ p->transmission_mode = TRANSMISSION_MODE_8K;
break;
default:
- printk("Unexpected value for transmission_mode\n");
+ printk(KERN_WARNING "Unexpected value for transmission_mode\n");
}
-
-
tmp = l64781_readreg(state, 0x05);
switch(tmp & 7) {
case 0:
- param->u.ofdm.code_rate_HP = FEC_1_2;
+ p->code_rate_HP = FEC_1_2;
break;
case 1:
- param->u.ofdm.code_rate_HP = FEC_2_3;
+ p->code_rate_HP = FEC_2_3;
break;
case 2:
- param->u.ofdm.code_rate_HP = FEC_3_4;
+ p->code_rate_HP = FEC_3_4;
break;
case 3:
- param->u.ofdm.code_rate_HP = FEC_5_6;
+ p->code_rate_HP = FEC_5_6;
break;
case 4:
- param->u.ofdm.code_rate_HP = FEC_7_8;
+ p->code_rate_HP = FEC_7_8;
break;
default:
printk("Unexpected value for code_rate_HP\n");
}
switch((tmp >> 3) & 7) {
case 0:
- param->u.ofdm.code_rate_LP = FEC_1_2;
+ p->code_rate_LP = FEC_1_2;
break;
case 1:
- param->u.ofdm.code_rate_LP = FEC_2_3;
+ p->code_rate_LP = FEC_2_3;
break;
case 2:
- param->u.ofdm.code_rate_LP = FEC_3_4;
+ p->code_rate_LP = FEC_3_4;
break;
case 3:
- param->u.ofdm.code_rate_LP = FEC_5_6;
+ p->code_rate_LP = FEC_5_6;
break;
case 4:
- param->u.ofdm.code_rate_LP = FEC_7_8;
+ p->code_rate_LP = FEC_7_8;
break;
default:
printk("Unexpected value for code_rate_LP\n");
}
-
tmp = l64781_readreg(state, 0x06);
switch(tmp & 3) {
case 0:
- param->u.ofdm.constellation = QPSK;
+ p->modulation = QPSK;
break;
case 1:
- param->u.ofdm.constellation = QAM_16;
+ p->modulation = QAM_16;
break;
case 2:
- param->u.ofdm.constellation = QAM_64;
+ p->modulation = QAM_64;
break;
default:
- printk("Unexpected value for constellation\n");
+ printk(KERN_WARNING "Unexpected value for modulation\n");
}
switch((tmp >> 2) & 7) {
case 0:
- param->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ p->hierarchy = HIERARCHY_NONE;
break;
case 1:
- param->u.ofdm.hierarchy_information = HIERARCHY_1;
+ p->hierarchy = HIERARCHY_1;
break;
case 2:
- param->u.ofdm.hierarchy_information = HIERARCHY_2;
+ p->hierarchy = HIERARCHY_2;
break;
case 3:
- param->u.ofdm.hierarchy_information = HIERARCHY_4;
+ p->hierarchy = HIERARCHY_4;
break;
default:
printk("Unexpected value for hierarchy\n");
@@ -341,12 +349,12 @@ static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters*
tmp = l64781_readreg (state, 0x1d);
- param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
+ p->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
tmp = (int) (l64781_readreg (state, 0x08) |
(l64781_readreg (state, 0x09) << 8) |
(l64781_readreg (state, 0x0a) << 16));
- param->frequency += tmp;
+ p->frequency += tmp;
return 0;
}
@@ -564,10 +572,9 @@ error:
}
static struct dvb_frontend_ops l64781_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "LSI L64781 DVB-T",
- .type = FE_OFDM,
/* .frequency_min = ???,*/
/* .frequency_max = ???,*/
.frequency_stepsize = 166666,
diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c
index 3272881cb112..1d2c47378cf8 100644
--- a/drivers/media/dvb/frontends/lgdt3305.c
+++ b/drivers/media/dvb/frontends/lgdt3305.c
@@ -266,7 +266,7 @@ fail:
}
static int lgdt3305_set_modulation(struct lgdt3305_state *state,
- struct dvb_frontend_parameters *param)
+ struct dtv_frontend_properties *p)
{
u8 opermode;
int ret;
@@ -279,7 +279,7 @@ static int lgdt3305_set_modulation(struct lgdt3305_state *state,
opermode &= ~0x03;
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
opermode |= 0x03;
break;
@@ -298,11 +298,11 @@ fail:
}
static int lgdt3305_set_filter_extension(struct lgdt3305_state *state,
- struct dvb_frontend_parameters *param)
+ struct dtv_frontend_properties *p)
{
int val;
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
val = 0;
break;
@@ -321,11 +321,11 @@ static int lgdt3305_set_filter_extension(struct lgdt3305_state *state,
/* ------------------------------------------------------------------------ */
static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state,
- struct dvb_frontend_parameters *param)
+ struct dtv_frontend_properties *p)
{
u16 agc_ref;
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
agc_ref = 0x32c4;
break;
@@ -348,11 +348,11 @@ static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state,
}
static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
- struct dvb_frontend_parameters *param)
+ struct dtv_frontend_properties *p)
{
u16 ifbw, rfbw, agcdelay;
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
agcdelay = 0x04c0;
rfbw = 0x8000;
@@ -398,11 +398,11 @@ static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
}
static int lgdt3305_agc_setup(struct lgdt3305_state *state,
- struct dvb_frontend_parameters *param)
+ struct dtv_frontend_properties *p)
{
int lockdten, acqen;
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
lockdten = 0;
acqen = 0;
@@ -432,15 +432,15 @@ static int lgdt3305_agc_setup(struct lgdt3305_state *state,
return -EINVAL;
}
- return lgdt3305_rfagc_loop(state, param);
+ return lgdt3305_rfagc_loop(state, p);
}
static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state,
- struct dvb_frontend_parameters *param)
+ struct dtv_frontend_properties *p)
{
u16 usref = 0;
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
if (state->cfg->usref_8vsb)
usref = state->cfg->usref_8vsb;
@@ -473,14 +473,14 @@ static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state,
/* ------------------------------------------------------------------------ */
static int lgdt3305_spectral_inversion(struct lgdt3305_state *state,
- struct dvb_frontend_parameters *param,
+ struct dtv_frontend_properties *p,
int inversion)
{
int ret;
lg_dbg("(%d)\n", inversion);
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7,
inversion ? 0xf9 : 0x79);
@@ -497,13 +497,13 @@ static int lgdt3305_spectral_inversion(struct lgdt3305_state *state,
}
static int lgdt3305_set_if(struct lgdt3305_state *state,
- struct dvb_frontend_parameters *param)
+ struct dtv_frontend_properties *p)
{
u16 if_freq_khz;
u8 nco1, nco2, nco3, nco4;
u64 nco;
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
if_freq_khz = state->cfg->vsb_if_khz;
break;
@@ -517,7 +517,7 @@ static int lgdt3305_set_if(struct lgdt3305_state *state,
nco = if_freq_khz / 10;
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
nco <<= 24;
do_div(nco, 625);
@@ -677,37 +677,37 @@ fail:
return ret;
}
-static int lgdt3304_set_parameters(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int lgdt3304_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct lgdt3305_state *state = fe->demodulator_priv;
int ret;
- lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
+ lg_dbg("(%d, %d)\n", p->frequency, p->modulation);
if (fe->ops.tuner_ops.set_params) {
- ret = fe->ops.tuner_ops.set_params(fe, param);
+ ret = fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
if (lg_fail(ret))
goto fail;
- state->current_frequency = param->frequency;
+ state->current_frequency = p->frequency;
}
- ret = lgdt3305_set_modulation(state, param);
+ ret = lgdt3305_set_modulation(state, p);
if (lg_fail(ret))
goto fail;
- ret = lgdt3305_passband_digital_agc(state, param);
+ ret = lgdt3305_passband_digital_agc(state, p);
if (lg_fail(ret))
goto fail;
- ret = lgdt3305_agc_setup(state, param);
+ ret = lgdt3305_agc_setup(state, p);
if (lg_fail(ret))
goto fail;
/* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
lgdt3305_write_reg(state, 0x030d, 0x00);
lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
@@ -718,7 +718,7 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe,
case QAM_64:
case QAM_256:
lgdt3305_write_reg(state, 0x030d, 0x14);
- ret = lgdt3305_set_if(state, param);
+ ret = lgdt3305_set_if(state, p);
if (lg_fail(ret))
goto fail;
break;
@@ -727,13 +727,13 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe,
}
- ret = lgdt3305_spectral_inversion(state, param,
+ ret = lgdt3305_spectral_inversion(state, p,
state->cfg->spectral_inversion
? 1 : 0);
if (lg_fail(ret))
goto fail;
- state->current_modulation = param->u.vsb.modulation;
+ state->current_modulation = p->modulation;
ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
if (lg_fail(ret))
@@ -747,34 +747,34 @@ fail:
return ret;
}
-static int lgdt3305_set_parameters(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int lgdt3305_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct lgdt3305_state *state = fe->demodulator_priv;
int ret;
- lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
+ lg_dbg("(%d, %d)\n", p->frequency, p->modulation);
if (fe->ops.tuner_ops.set_params) {
- ret = fe->ops.tuner_ops.set_params(fe, param);
+ ret = fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
if (lg_fail(ret))
goto fail;
- state->current_frequency = param->frequency;
+ state->current_frequency = p->frequency;
}
- ret = lgdt3305_set_modulation(state, param);
+ ret = lgdt3305_set_modulation(state, p);
if (lg_fail(ret))
goto fail;
- ret = lgdt3305_passband_digital_agc(state, param);
+ ret = lgdt3305_passband_digital_agc(state, p);
if (lg_fail(ret))
goto fail;
- ret = lgdt3305_set_agc_power_ref(state, param);
+ ret = lgdt3305_set_agc_power_ref(state, p);
if (lg_fail(ret))
goto fail;
- ret = lgdt3305_agc_setup(state, param);
+ ret = lgdt3305_agc_setup(state, p);
if (lg_fail(ret))
goto fail;
@@ -786,20 +786,20 @@ static int lgdt3305_set_parameters(struct dvb_frontend *fe,
if (lg_fail(ret))
goto fail;
- ret = lgdt3305_set_if(state, param);
+ ret = lgdt3305_set_if(state, p);
if (lg_fail(ret))
goto fail;
- ret = lgdt3305_spectral_inversion(state, param,
+ ret = lgdt3305_spectral_inversion(state, p,
state->cfg->spectral_inversion
? 1 : 0);
if (lg_fail(ret))
goto fail;
- ret = lgdt3305_set_filter_extension(state, param);
+ ret = lgdt3305_set_filter_extension(state, p);
if (lg_fail(ret))
goto fail;
- state->current_modulation = param->u.vsb.modulation;
+ state->current_modulation = p->modulation;
ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
if (lg_fail(ret))
@@ -813,15 +813,15 @@ fail:
return ret;
}
-static int lgdt3305_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int lgdt3305_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct lgdt3305_state *state = fe->demodulator_priv;
lg_dbg("\n");
- param->u.vsb.modulation = state->current_modulation;
- param->frequency = state->current_frequency;
+ p->modulation = state->current_modulation;
+ p->frequency = state->current_frequency;
return 0;
}
@@ -1166,9 +1166,9 @@ fail:
EXPORT_SYMBOL(lgdt3305_attach);
static struct dvb_frontend_ops lgdt3304_ops = {
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name = "LG Electronics LGDT3304 VSB/QAM Frontend",
- .type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
@@ -1188,9 +1188,9 @@ static struct dvb_frontend_ops lgdt3304_ops = {
};
static struct dvb_frontend_ops lgdt3305_ops = {
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name = "LG Electronics LGDT3305 VSB/QAM Frontend",
- .type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 43971e63baa7..e046622df0e4 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -104,8 +104,8 @@ static int i2c_write_demod_bytes (struct lgdt330x_state* state,
* then reads the data returned for (len) bytes.
*/
-static u8 i2c_read_demod_bytes (struct lgdt330x_state* state,
- enum I2C_REG reg, u8* buf, int len)
+static int i2c_read_demod_bytes(struct lgdt330x_state *state,
+ enum I2C_REG reg, u8 *buf, int len)
{
u8 wr [] = { reg };
struct i2c_msg msg [] = {
@@ -118,6 +118,8 @@ static u8 i2c_read_demod_bytes (struct lgdt330x_state* state,
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret);
+ if (ret >= 0)
+ ret = -EIO;
} else {
ret = 0;
}
@@ -288,6 +290,8 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
int err;
u8 buf[2];
+ *ucblocks = 0;
+
switch (state->config->demod_chip) {
case LGDT3302:
err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
@@ -302,14 +306,16 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
"Only LGDT3302 and LGDT3303 are supported chips.\n");
err = -ENODEV;
}
+ if (err < 0)
+ return err;
*ucblocks = (buf[0] << 8) | buf[1];
return 0;
}
-static int lgdt330x_set_parameters(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *param)
+static int lgdt330x_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
/*
* Array of byte pairs <address, value>
* to initialize 8VSB for lgdt3303 chip 50 MHz IF
@@ -343,10 +349,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 };
- int err;
+ int err = 0;
/* Change only if we are actually changing the modulation */
- if (state->current_modulation != param->u.vsb.modulation) {
- switch(param->u.vsb.modulation) {
+ if (state->current_modulation != p->modulation) {
+ switch (p->modulation) {
case VSB_8:
dprintk("%s: VSB_8 MODE\n", __func__);
@@ -395,9 +401,14 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
}
break;
default:
- printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, param->u.vsb.modulation);
+ printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, p->modulation);
return -1;
}
+ if (err < 0)
+ printk(KERN_WARNING "lgdt330x: %s: error blasting "
+ "bytes to lgdt3303 for modulation type(%d)\n",
+ __func__, p->modulation);
+
/*
* select serial or parallel MPEG harware interface
* Serial: 0x04 for LGDT3302 or 0x40 for LGDT3303
@@ -410,29 +421,29 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
sizeof(top_ctrl_cfg));
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
- state->current_modulation = param->u.vsb.modulation;
+ state->current_modulation = p->modulation;
}
/* Tune to the specified frequency */
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, param);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
/* Keep track of the new frequency */
/* FIXME this is the wrong way to do this... */
/* The tuner is shared with the video4linux analog API */
- state->current_frequency = param->frequency;
+ state->current_frequency = p->frequency;
lgdt330x_SwReset(state);
return 0;
}
-static int lgdt330x_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* param)
+static int lgdt330x_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct lgdt330x_state *state = fe->demodulator_priv;
- param->frequency = state->current_frequency;
+ p->frequency = state->current_frequency;
return 0;
}
@@ -762,9 +773,9 @@ error:
}
static struct dvb_frontend_ops lgdt3302_ops = {
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name= "LG Electronics LGDT3302 VSB/QAM Frontend",
- .type = FE_ATSC,
.frequency_min= 54000000,
.frequency_max= 858000000,
.frequency_stepsize= 62500,
@@ -785,9 +796,9 @@ static struct dvb_frontend_ops lgdt3302_ops = {
};
static struct dvb_frontend_ops lgdt3303_ops = {
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name= "LG Electronics LGDT3303 VSB/QAM Frontend",
- .type = FE_ATSC,
.frequency_min= 54000000,
.frequency_max= 858000000,
.frequency_stepsize= 62500,
diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c
index bb37ed289a05..2cec8041a106 100644
--- a/drivers/media/dvb/frontends/lgs8gl5.c
+++ b/drivers/media/dvb/frontends/lgs8gl5.c
@@ -311,18 +311,18 @@ lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
static int
-lgs8gl5_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+lgs8gl5_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct lgs8gl5_state *state = fe->demodulator_priv;
dprintk("%s\n", __func__);
- if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ)
+ if (p->bandwidth_hz != 8000000)
return -EINVAL;
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -336,22 +336,21 @@ lgs8gl5_set_frontend(struct dvb_frontend *fe,
static int
-lgs8gl5_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+lgs8gl5_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct lgs8gl5_state *state = fe->demodulator_priv;
u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
- struct dvb_ofdm_parameters *o = &p->u.ofdm;
p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
- o->code_rate_HP = FEC_1_2;
- o->code_rate_LP = FEC_7_8;
- o->guard_interval = GUARD_INTERVAL_1_32;
- o->transmission_mode = TRANSMISSION_MODE_2K;
- o->constellation = QAM_64;
- o->hierarchy_information = HIERARCHY_NONE;
- o->bandwidth = BANDWIDTH_8_MHZ;
+ p->code_rate_HP = FEC_1_2;
+ p->code_rate_LP = FEC_7_8;
+ p->guard_interval = GUARD_INTERVAL_1_32;
+ p->transmission_mode = TRANSMISSION_MODE_2K;
+ p->modulation = QAM_64;
+ p->hierarchy = HIERARCHY_NONE;
+ p->bandwidth_hz = 8000000;
return 0;
}
@@ -413,9 +412,9 @@ EXPORT_SYMBOL(lgs8gl5_attach);
static struct dvb_frontend_ops lgs8gl5_ops = {
+ .delsys = { SYS_DMBTH },
.info = {
.name = "Legend Silicon LGS-8GL5 DMB-TH",
- .type = FE_OFDM,
.frequency_min = 474000000,
.frequency_max = 858000000,
.frequency_stepsize = 10000,
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index 1172b54689f8..4de1d3520cd2 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -669,16 +669,16 @@ static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
return lgs8gxx_write_reg(priv, buf[0], buf[1]);
}
-static int lgs8gxx_set_fe(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fe_params)
+static int lgs8gxx_set_fe(struct dvb_frontend *fe)
{
+
struct lgs8gxx_state *priv = fe->demodulator_priv;
dprintk("%s\n", __func__);
/* set frequency */
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, fe_params);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -691,9 +691,9 @@ static int lgs8gxx_set_fe(struct dvb_frontend *fe,
return 0;
}
-static int lgs8gxx_get_fe(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fe_params)
+static int lgs8gxx_get_fe(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
dprintk("%s\n", __func__);
/* TODO: get real readings from device */
@@ -701,21 +701,21 @@ static int lgs8gxx_get_fe(struct dvb_frontend *fe,
fe_params->inversion = INVERSION_OFF;
/* bandwidth */
- fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ fe_params->bandwidth_hz = 8000000;
- fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
- fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
+ fe_params->code_rate_HP = FEC_AUTO;
+ fe_params->code_rate_LP = FEC_AUTO;
- fe_params->u.ofdm.constellation = QAM_AUTO;
+ fe_params->modulation = QAM_AUTO;
/* transmission mode */
- fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+ fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
/* guard interval */
- fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+ fe_params->guard_interval = GUARD_INTERVAL_AUTO;
/* hierarchy */
- fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ fe_params->hierarchy = HIERARCHY_NONE;
return 0;
}
@@ -994,9 +994,9 @@ static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
}
static struct dvb_frontend_ops lgs8gxx_ops = {
+ .delsys = { SYS_DMBTH },
.info = {
.name = "Legend Silicon LGS8913/LGS8GXX DMB-TH",
- .type = FE_OFDM,
.frequency_min = 474000000,
.frequency_max = 858000000,
.frequency_stepsize = 10000,
diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c
new file mode 100644
index 000000000000..045ee5a6f7ae
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88rs2000.c
@@ -0,0 +1,904 @@
+/*
+ Driver for M88RS2000 demodulator and tuner
+
+ Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com)
+ Beta Driver
+
+ Include various calculation code from DS3000 driver.
+ Copyright (C) 2009 Konstantin Dimitrov.
+
+ 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/module.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+
+#include "dvb_frontend.h"
+#include "m88rs2000.h"
+
+struct m88rs2000_state {
+ struct i2c_adapter *i2c;
+ const struct m88rs2000_config *config;
+ struct dvb_frontend frontend;
+ u8 no_lock_count;
+ u32 tuner_frequency;
+ u32 symbol_rate;
+ fe_code_rate_t fec_inner;
+ u8 tuner_level;
+ int errmode;
+};
+
+static int m88rs2000_debug;
+
+module_param_named(debug, m88rs2000_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define dprintk(level, args...) do { \
+ if (level & m88rs2000_debug) \
+ printk(KERN_DEBUG "m88rs2000-fe: " args); \
+} while (0)
+
+#define deb_info(args...) dprintk(0x01, args)
+#define info(format, arg...) \
+ printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg)
+
+static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
+ u8 reg, u8 data)
+{
+ int ret;
+ u8 addr = (tuner == 0) ? state->config->tuner_addr :
+ state->config->demod_addr;
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = {
+ .addr = addr,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+ "ret == %i)\n", __func__, reg, data, ret);
+
+ return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data)
+{
+ return m88rs2000_writereg(state, 1, reg, data);
+}
+
+static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data)
+{
+ m88rs2000_demod_write(state, 0x81, 0x84);
+ udelay(10);
+ return m88rs2000_writereg(state, 0, reg, data);
+
+}
+
+static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+
+ if (len != 2)
+ return -EINVAL;
+
+ return m88rs2000_writereg(state, 1, buf[0], buf[1]);
+}
+
+static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+ u8 addr = (tuner == 0) ? state->config->tuner_addr :
+ state->config->demod_addr;
+ struct i2c_msg msg[] = {
+ {
+ .addr = addr,
+ .flags = 0,
+ .buf = b0,
+ .len = 1
+ }, {
+ .addr = addr,
+ .flags = I2C_M_RD,
+ .buf = b1,
+ .len = 1
+ }
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ deb_info("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+ __func__, reg, ret);
+
+ return b1[0];
+}
+
+static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg)
+{
+ return m88rs2000_readreg(state, 1, reg);
+}
+
+static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg)
+{
+ m88rs2000_demod_write(state, 0x81, 0x85);
+ udelay(10);
+ return m88rs2000_readreg(state, 0, reg);
+}
+
+static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ int ret;
+ u32 temp;
+ u8 b[3];
+
+ if ((srate < 1000000) || (srate > 45000000))
+ return -EINVAL;
+
+ temp = srate / 1000;
+ temp *= 11831;
+ temp /= 68;
+ temp -= 3;
+
+ b[0] = (u8) (temp >> 16) & 0xff;
+ b[1] = (u8) (temp >> 8) & 0xff;
+ b[2] = (u8) temp & 0xff;
+ ret = m88rs2000_demod_write(state, 0x93, b[2]);
+ ret |= m88rs2000_demod_write(state, 0x94, b[1]);
+ ret |= m88rs2000_demod_write(state, 0x95, b[0]);
+
+ deb_info("m88rs2000: m88rs2000_set_symbolrate\n");
+ return ret;
+}
+
+static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *m)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+
+ int i;
+ u8 reg;
+ deb_info("%s\n", __func__);
+ m88rs2000_demod_write(state, 0x9a, 0x30);
+ reg = m88rs2000_demod_read(state, 0xb2);
+ reg &= 0x3f;
+ m88rs2000_demod_write(state, 0xb2, reg);
+ for (i = 0; i < m->msg_len; i++)
+ m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]);
+
+ reg = m88rs2000_demod_read(state, 0xb1);
+ reg &= 0x87;
+ reg |= ((m->msg_len - 1) << 3) | 0x07;
+ reg &= 0x7f;
+ m88rs2000_demod_write(state, 0xb1, reg);
+
+ for (i = 0; i < 15; i++) {
+ if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0)
+ break;
+ msleep(20);
+ }
+
+ reg = m88rs2000_demod_read(state, 0xb1);
+ if ((reg & 0x40) > 0x0) {
+ reg &= 0x7f;
+ reg |= 0x40;
+ m88rs2000_demod_write(state, 0xb1, reg);
+ }
+
+ reg = m88rs2000_demod_read(state, 0xb2);
+ reg &= 0x3f;
+ reg |= 0x80;
+ m88rs2000_demod_write(state, 0xb2, reg);
+ m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+
+ return 0;
+}
+
+static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe,
+ fe_sec_mini_cmd_t burst)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ u8 reg0, reg1;
+ deb_info("%s\n", __func__);
+ m88rs2000_demod_write(state, 0x9a, 0x30);
+ msleep(50);
+ reg0 = m88rs2000_demod_read(state, 0xb1);
+ reg1 = m88rs2000_demod_read(state, 0xb2);
+ /* TODO complete this section */
+ m88rs2000_demod_write(state, 0xb2, reg1);
+ m88rs2000_demod_write(state, 0xb1, reg0);
+ m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+ return 0;
+}
+
+static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ u8 reg0, reg1;
+ m88rs2000_demod_write(state, 0x9a, 0x30);
+ reg0 = m88rs2000_demod_read(state, 0xb1);
+ reg1 = m88rs2000_demod_read(state, 0xb2);
+
+ reg1 &= 0x3f;
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ reg0 |= 0x4;
+ reg0 &= 0xbc;
+ break;
+ case SEC_TONE_OFF:
+ reg1 |= 0x80;
+ break;
+ default:
+ break;
+ }
+ m88rs2000_demod_write(state, 0xb2, reg1);
+ m88rs2000_demod_write(state, 0xb1, reg0);
+ m88rs2000_demod_write(state, 0x9a, 0xb0);
+ return 0;
+}
+
+struct inittab {
+ u8 cmd;
+ u8 reg;
+ u8 val;
+};
+
+struct inittab m88rs2000_setup[] = {
+ {DEMOD_WRITE, 0x9a, 0x30},
+ {DEMOD_WRITE, 0x00, 0x01},
+ {WRITE_DELAY, 0x19, 0x00},
+ {DEMOD_WRITE, 0x00, 0x00},
+ {DEMOD_WRITE, 0x9a, 0xb0},
+ {DEMOD_WRITE, 0x81, 0xc1},
+ {TUNER_WRITE, 0x42, 0x73},
+ {TUNER_WRITE, 0x05, 0x07},
+ {TUNER_WRITE, 0x20, 0x27},
+ {TUNER_WRITE, 0x07, 0x02},
+ {TUNER_WRITE, 0x11, 0xff},
+ {TUNER_WRITE, 0x60, 0xf9},
+ {TUNER_WRITE, 0x08, 0x01},
+ {TUNER_WRITE, 0x00, 0x41},
+ {DEMOD_WRITE, 0x81, 0x81},
+ {DEMOD_WRITE, 0x86, 0xc6},
+ {DEMOD_WRITE, 0x9a, 0x30},
+ {DEMOD_WRITE, 0xf0, 0x22},
+ {DEMOD_WRITE, 0xf1, 0xbf},
+ {DEMOD_WRITE, 0xb0, 0x45},
+ {DEMOD_WRITE, 0xb2, 0x01}, /* set voltage pin always set 1*/
+ {DEMOD_WRITE, 0x9a, 0xb0},
+ {0xff, 0xaa, 0xff}
+};
+
+struct inittab m88rs2000_shutdown[] = {
+ {DEMOD_WRITE, 0x9a, 0x30},
+ {DEMOD_WRITE, 0xb0, 0x00},
+ {DEMOD_WRITE, 0xf1, 0x89},
+ {DEMOD_WRITE, 0x00, 0x01},
+ {DEMOD_WRITE, 0x9a, 0xb0},
+ {TUNER_WRITE, 0x00, 0x40},
+ {DEMOD_WRITE, 0x81, 0x81},
+ {0xff, 0xaa, 0xff}
+};
+
+struct inittab tuner_reset[] = {
+ {TUNER_WRITE, 0x42, 0x73},
+ {TUNER_WRITE, 0x05, 0x07},
+ {TUNER_WRITE, 0x20, 0x27},
+ {TUNER_WRITE, 0x07, 0x02},
+ {TUNER_WRITE, 0x11, 0xff},
+ {TUNER_WRITE, 0x60, 0xf9},
+ {TUNER_WRITE, 0x08, 0x01},
+ {TUNER_WRITE, 0x00, 0x41},
+ {0xff, 0xaa, 0xff}
+};
+
+struct inittab fe_reset[] = {
+ {DEMOD_WRITE, 0x00, 0x01},
+ {DEMOD_WRITE, 0xf1, 0xbf},
+ {DEMOD_WRITE, 0x00, 0x01},
+ {DEMOD_WRITE, 0x20, 0x81},
+ {DEMOD_WRITE, 0x21, 0x80},
+ {DEMOD_WRITE, 0x10, 0x33},
+ {DEMOD_WRITE, 0x11, 0x44},
+ {DEMOD_WRITE, 0x12, 0x07},
+ {DEMOD_WRITE, 0x18, 0x20},
+ {DEMOD_WRITE, 0x28, 0x04},
+ {DEMOD_WRITE, 0x29, 0x8e},
+ {DEMOD_WRITE, 0x3b, 0xff},
+ {DEMOD_WRITE, 0x32, 0x10},
+ {DEMOD_WRITE, 0x33, 0x02},
+ {DEMOD_WRITE, 0x34, 0x30},
+ {DEMOD_WRITE, 0x35, 0xff},
+ {DEMOD_WRITE, 0x38, 0x50},
+ {DEMOD_WRITE, 0x39, 0x68},
+ {DEMOD_WRITE, 0x3c, 0x7f},
+ {DEMOD_WRITE, 0x3d, 0x0f},
+ {DEMOD_WRITE, 0x45, 0x20},
+ {DEMOD_WRITE, 0x46, 0x24},
+ {DEMOD_WRITE, 0x47, 0x7c},
+ {DEMOD_WRITE, 0x48, 0x16},
+ {DEMOD_WRITE, 0x49, 0x04},
+ {DEMOD_WRITE, 0x4a, 0x01},
+ {DEMOD_WRITE, 0x4b, 0x78},
+ {DEMOD_WRITE, 0X4d, 0xd2},
+ {DEMOD_WRITE, 0x4e, 0x6d},
+ {DEMOD_WRITE, 0x50, 0x30},
+ {DEMOD_WRITE, 0x51, 0x30},
+ {DEMOD_WRITE, 0x54, 0x7b},
+ {DEMOD_WRITE, 0x56, 0x09},
+ {DEMOD_WRITE, 0x58, 0x59},
+ {DEMOD_WRITE, 0x59, 0x37},
+ {DEMOD_WRITE, 0x63, 0xfa},
+ {0xff, 0xaa, 0xff}
+};
+
+struct inittab fe_trigger[] = {
+ {DEMOD_WRITE, 0x97, 0x04},
+ {DEMOD_WRITE, 0x99, 0x77},
+ {DEMOD_WRITE, 0x9b, 0x64},
+ {DEMOD_WRITE, 0x9e, 0x00},
+ {DEMOD_WRITE, 0x9f, 0xf8},
+ {DEMOD_WRITE, 0xa0, 0x20},
+ {DEMOD_WRITE, 0xa1, 0xe0},
+ {DEMOD_WRITE, 0xa3, 0x38},
+ {DEMOD_WRITE, 0x98, 0xff},
+ {DEMOD_WRITE, 0xc0, 0x0f},
+ {DEMOD_WRITE, 0x89, 0x01},
+ {DEMOD_WRITE, 0x00, 0x00},
+ {WRITE_DELAY, 0x0a, 0x00},
+ {DEMOD_WRITE, 0x00, 0x01},
+ {DEMOD_WRITE, 0x00, 0x00},
+ {DEMOD_WRITE, 0x9a, 0xb0},
+ {0xff, 0xaa, 0xff}
+};
+
+static int m88rs2000_tab_set(struct m88rs2000_state *state,
+ struct inittab *tab)
+{
+ int ret = 0;
+ u8 i;
+ if (tab == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < 255; i++) {
+ switch (tab[i].cmd) {
+ case 0x01:
+ ret = m88rs2000_demod_write(state, tab[i].reg,
+ tab[i].val);
+ break;
+ case 0x02:
+ ret = m88rs2000_tuner_write(state, tab[i].reg,
+ tab[i].val);
+ break;
+ case 0x10:
+ if (tab[i].reg > 0)
+ mdelay(tab[i].reg);
+ break;
+ case 0xff:
+ if (tab[i].reg == 0xaa && tab[i].val == 0xff)
+ return 0;
+ case 0x00:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ret < 0)
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+ deb_info("%s: %s\n", __func__,
+ volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+ volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+ return 0;
+}
+
+static int m88rs2000_startup(struct m88rs2000_state *state)
+{
+ int ret = 0;
+ u8 reg;
+
+ reg = m88rs2000_tuner_read(state, 0x00);
+ if ((reg & 0x40) == 0)
+ ret = -ENODEV;
+
+ return ret;
+}
+
+static int m88rs2000_init(struct dvb_frontend *fe)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ int ret;
+
+ deb_info("m88rs2000: init chip\n");
+ /* Setup frontend from shutdown/cold */
+ ret = m88rs2000_tab_set(state, m88rs2000_setup);
+
+ return ret;
+}
+
+static int m88rs2000_sleep(struct dvb_frontend *fe)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ int ret;
+ /* Shutdown the frondend */
+ ret = m88rs2000_tab_set(state, m88rs2000_shutdown);
+ return ret;
+}
+
+static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ u8 reg = m88rs2000_demod_read(state, 0x8c);
+
+ *status = 0;
+
+ if ((reg & 0x7) == 0x7) {
+ *status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI
+ | FE_HAS_LOCK;
+ if (state->config->set_ts_params)
+ state->config->set_ts_params(fe, CALL_IS_READ);
+ }
+ return 0;
+}
+
+/* Extact code for these unknown but lmedm04 driver uses interupt callbacks */
+
+static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ deb_info("m88rs2000_read_ber %d\n", *ber);
+ *ber = 0;
+ return 0;
+}
+
+static int m88rs2000_read_signal_strength(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ *strength = 0;
+ return 0;
+}
+
+static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ deb_info("m88rs2000_read_snr %d\n", *snr);
+ *snr = 0;
+ return 0;
+}
+
+static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ deb_info("m88rs2000_read_ber %d\n", *ucblocks);
+ *ucblocks = 0;
+ return 0;
+}
+
+static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset)
+{
+ int ret;
+ ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset);
+ ret |= m88rs2000_tuner_write(state, 0x51, 0x1f);
+ ret |= m88rs2000_tuner_write(state, 0x50, offset);
+ ret |= m88rs2000_tuner_write(state, 0x50, 0x00);
+ msleep(20);
+ return ret;
+}
+
+static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ int reg;
+ reg = m88rs2000_tuner_read(state, 0x3d);
+ reg &= 0x7f;
+ if (reg < 0x16)
+ reg = 0xa1;
+ else if (reg == 0x16)
+ reg = 0x99;
+ else
+ reg = 0xf9;
+
+ m88rs2000_tuner_write(state, 0x60, reg);
+ reg = m88rs2000_tuner_gate_ctrl(state, 0x08);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ return reg;
+}
+
+static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ int ret;
+ u32 frequency = c->frequency;
+ s32 offset_khz;
+ s32 tmp;
+ u32 symbol_rate = (c->symbol_rate / 1000);
+ u32 f3db, gdiv28;
+ u16 value, ndiv, lpf_coeff;
+ u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
+ u8 lo = 0x01, div4 = 0x0;
+
+ /* Reset Tuner */
+ ret = m88rs2000_tab_set(state, tuner_reset);
+
+ /* Calculate frequency divider */
+ if (frequency < 1060000) {
+ lo |= 0x10;
+ div4 = 0x1;
+ ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ;
+ } else
+ ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ;
+ ndiv = ndiv + ndiv % 2;
+ ndiv = ndiv - 1024;
+
+ ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo);
+
+ /* Set frequency divider */
+ ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf);
+ ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff);
+
+ ret |= m88rs2000_tuner_write(state, 0x03, 0x06);
+ ret |= m88rs2000_tuner_gate_ctrl(state, 0x10);
+ if (ret < 0)
+ return -ENODEV;
+
+ /* Tuner Frequency Range */
+ ret = m88rs2000_tuner_write(state, 0x10, lo);
+
+ ret |= m88rs2000_tuner_gate_ctrl(state, 0x08);
+
+ /* Tuner RF */
+ ret |= m88rs2000_set_tuner_rf(fe);
+
+ gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
+ ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff);
+ ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
+ if (ret < 0)
+ return -ENODEV;
+
+ value = m88rs2000_tuner_read(state, 0x26);
+
+ f3db = (symbol_rate * 135) / 200 + 2000;
+ f3db += FREQ_OFFSET_LOW_SYM_RATE;
+ if (f3db < 7000)
+ f3db = 7000;
+ if (f3db > 40000)
+ f3db = 40000;
+
+ gdiv28 = gdiv28 * 207 / (value * 2 + 151);
+ mlpf_max = gdiv28 * 135 / 100;
+ mlpf_min = gdiv28 * 78 / 100;
+ if (mlpf_max > 63)
+ mlpf_max = 63;
+
+ lpf_coeff = 2766;
+
+ nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
+ (FE_CRYSTAL_KHZ / 1000) + 1) / 2;
+ if (nlpf > 23)
+ nlpf = 23;
+ if (nlpf < 1)
+ nlpf = 1;
+
+ lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
+ * lpf_coeff * 2 / f3db + 1) / 2;
+
+ if (lpf_mxdiv < mlpf_min) {
+ nlpf++;
+ lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
+ * lpf_coeff * 2 / f3db + 1) / 2;
+ }
+
+ if (lpf_mxdiv > mlpf_max)
+ lpf_mxdiv = mlpf_max;
+
+ ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv);
+ ret |= m88rs2000_tuner_write(state, 0x06, nlpf);
+
+ ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
+
+ ret |= m88rs2000_tuner_gate_ctrl(state, 0x01);
+
+ msleep(80);
+ /* calculate offset assuming 96000kHz*/
+ offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ
+ / 14 / (div4 + 1) / 2;
+
+ offset_khz -= frequency;
+
+ tmp = offset_khz;
+ tmp *= 65536;
+
+ tmp = (2 * tmp + 96000) / (2 * 96000);
+ if (tmp < 0)
+ tmp += 65536;
+
+ *offset = tmp & 0xffff;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return (ret < 0) ? -EINVAL : 0;
+}
+
+static int m88rs2000_set_fec(struct m88rs2000_state *state,
+ fe_code_rate_t fec)
+{
+ int ret;
+ u16 fec_set;
+ switch (fec) {
+ /* This is not confirmed kept for reference */
+/* case FEC_1_2:
+ fec_set = 0x88;
+ break;
+ case FEC_2_3:
+ fec_set = 0x68;
+ break;
+ case FEC_3_4:
+ fec_set = 0x48;
+ break;
+ case FEC_5_6:
+ fec_set = 0x28;
+ break;
+ case FEC_7_8:
+ fec_set = 0x18;
+ break; */
+ case FEC_AUTO:
+ default:
+ fec_set = 0x08;
+ }
+ ret = m88rs2000_demod_write(state, 0x76, fec_set);
+
+ return 0;
+}
+
+
+static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
+{
+ u8 reg;
+ m88rs2000_demod_write(state, 0x9a, 0x30);
+ reg = m88rs2000_demod_read(state, 0x76);
+ m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+ switch (reg) {
+ case 0x88:
+ return FEC_1_2;
+ case 0x68:
+ return FEC_2_3;
+ case 0x48:
+ return FEC_3_4;
+ case 0x28:
+ return FEC_5_6;
+ case 0x18:
+ return FEC_7_8;
+ case 0x08:
+ default:
+ break;
+ }
+
+ return FEC_AUTO;
+}
+
+static int m88rs2000_set_frontend(struct dvb_frontend *fe)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ fe_status_t status;
+ int i, ret;
+ u16 offset = 0;
+ u8 reg;
+
+ state->no_lock_count = 0;
+
+ if (c->delivery_system != SYS_DVBS) {
+ deb_info("%s: unsupported delivery "
+ "system selected (%d)\n",
+ __func__, c->delivery_system);
+ return -EOPNOTSUPP;
+ }
+
+ /* Set Tuner */
+ ret = m88rs2000_set_tuner(fe, &offset);
+ if (ret < 0)
+ return -ENODEV;
+
+ ret = m88rs2000_demod_write(state, 0x9a, 0x30);
+ /* Unknown usually 0xc6 sometimes 0xc1 */
+ reg = m88rs2000_demod_read(state, 0x86);
+ ret |= m88rs2000_demod_write(state, 0x86, reg);
+ /* Offset lower nibble always 0 */
+ ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8));
+ ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0);
+
+
+ /* Reset Demod */
+ ret = m88rs2000_tab_set(state, fe_reset);
+ if (ret < 0)
+ return -ENODEV;
+
+ /* Unknown */
+ reg = m88rs2000_demod_read(state, 0x70);
+ ret = m88rs2000_demod_write(state, 0x70, reg);
+
+ /* Set FEC */
+ ret |= m88rs2000_set_fec(state, c->fec_inner);
+ ret |= m88rs2000_demod_write(state, 0x85, 0x1);
+ ret |= m88rs2000_demod_write(state, 0x8a, 0xbf);
+ ret |= m88rs2000_demod_write(state, 0x8d, 0x1e);
+ ret |= m88rs2000_demod_write(state, 0x90, 0xf1);
+ ret |= m88rs2000_demod_write(state, 0x91, 0x08);
+
+ if (ret < 0)
+ return -ENODEV;
+
+ /* Set Symbol Rate */
+ ret = m88rs2000_set_symbolrate(fe, c->symbol_rate);
+ if (ret < 0)
+ return -ENODEV;
+
+ /* Set up Demod */
+ ret = m88rs2000_tab_set(state, fe_trigger);
+ if (ret < 0)
+ return -ENODEV;
+
+ for (i = 0; i < 25; i++) {
+ u8 reg = m88rs2000_demod_read(state, 0x8c);
+ if ((reg & 0x7) == 0x7) {
+ status = FE_HAS_LOCK;
+ break;
+ }
+ state->no_lock_count++;
+ if (state->no_lock_count > 15) {
+ reg = m88rs2000_demod_read(state, 0x70);
+ reg ^= 0x4;
+ m88rs2000_demod_write(state, 0x70, reg);
+ state->no_lock_count = 0;
+ }
+ if (state->no_lock_count == 20)
+ m88rs2000_set_tuner_rf(fe);
+ msleep(20);
+ }
+
+ if (status & FE_HAS_LOCK) {
+ state->fec_inner = m88rs2000_get_fec(state);
+ /* Uknown suspect SNR level */
+ reg = m88rs2000_demod_read(state, 0x65);
+ }
+
+ state->tuner_frequency = c->frequency;
+ state->symbol_rate = c->symbol_rate;
+ return 0;
+}
+
+static int m88rs2000_get_frontend(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ c->fec_inner = state->fec_inner;
+ c->frequency = state->tuner_frequency;
+ c->symbol_rate = state->symbol_rate;
+ return 0;
+}
+
+static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+
+ if (enable)
+ m88rs2000_demod_write(state, 0x81, 0x84);
+ else
+ m88rs2000_demod_write(state, 0x81, 0x81);
+ udelay(10);
+ return 0;
+}
+
+static void m88rs2000_release(struct dvb_frontend *fe)
+{
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops m88rs2000_ops = {
+ .delsys = { SYS_DVBS },
+ .info = {
+ .name = "M88RS2000 DVB-S",
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 1000, /* kHz for QPSK frontends */
+ .frequency_tolerance = 5000,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .symbol_rate_tolerance = 500, /* ppm */
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+ FE_CAN_QPSK |
+ FE_CAN_FEC_AUTO
+ },
+
+ .release = m88rs2000_release,
+ .init = m88rs2000_init,
+ .sleep = m88rs2000_sleep,
+ .write = m88rs2000_write,
+ .i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl,
+ .read_status = m88rs2000_read_status,
+ .read_ber = m88rs2000_read_ber,
+ .read_signal_strength = m88rs2000_read_signal_strength,
+ .read_snr = m88rs2000_read_snr,
+ .read_ucblocks = m88rs2000_read_ucblocks,
+ .diseqc_send_master_cmd = m88rs2000_send_diseqc_msg,
+ .diseqc_send_burst = m88rs2000_send_diseqc_burst,
+ .set_tone = m88rs2000_set_tone,
+ .set_voltage = m88rs2000_set_voltage,
+
+ .set_frontend = m88rs2000_set_frontend,
+ .get_frontend = m88rs2000_get_frontend,
+};
+
+struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct m88rs2000_state *state = NULL;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct m88rs2000_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ state->tuner_frequency = 0;
+ state->symbol_rate = 0;
+ state->fec_inner = 0;
+
+ if (m88rs2000_startup(state) < 0)
+ goto error;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &m88rs2000_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ kfree(state);
+
+ return NULL;
+}
+EXPORT_SYMBOL(m88rs2000_attach);
+
+MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.13");
+
diff --git a/drivers/media/dvb/frontends/m88rs2000.h b/drivers/media/dvb/frontends/m88rs2000.h
new file mode 100644
index 000000000000..59acdb696873
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88rs2000.h
@@ -0,0 +1,66 @@
+/*
+ Driver for M88RS2000 demodulator
+
+ 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 M88RS2000_H
+#define M88RS2000_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct m88rs2000_config {
+ /* Demodulator i2c address */
+ u8 demod_addr;
+ /* Tuner address */
+ u8 tuner_addr;
+
+ u8 *inittab;
+
+ /* minimum delay before retuning */
+ int min_delay_ms;
+
+ int (*set_ts_params)(struct dvb_frontend *, int);
+};
+
+enum {
+ CALL_IS_SET_FRONTEND = 0x0,
+ CALL_IS_READ,
+};
+
+#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \
+ defined(MODULE))
+extern struct dvb_frontend *m88rs2000_attach(
+ const struct m88rs2000_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *m88rs2000_attach(
+ const struct m88rs2000_config *config, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_M88RS2000 */
+
+#define FE_CRYSTAL_KHZ 27000
+#define FREQ_OFFSET_LOW_SYM_RATE 3000
+
+enum {
+ DEMOD_WRITE = 0x1,
+ TUNER_WRITE,
+ WRITE_DELAY = 0x10,
+};
+#endif /* M88RS2000_H */
diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c
index c283112051b1..9ae40abfd71a 100644
--- a/drivers/media/dvb/frontends/mb86a16.c
+++ b/drivers/media/dvb/frontends/mb86a16.c
@@ -1621,13 +1621,13 @@ err:
return -EREMOTEIO;
}
-static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mb86a16_state *state = fe->demodulator_priv;
state->frequency = p->frequency / 1000;
- state->srate = p->u.qpsk.symbol_rate / 1000;
+ state->srate = p->symbol_rate / 1000;
if (!mb86a16_set_fe(state)) {
dprintk(verbose, MB86A16_ERROR, 1, "Successfully acquired LOCK");
@@ -1814,9 +1814,9 @@ static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops mb86a16_ops = {
+ .delsys = { SYS_DVBS },
.info = {
.name = "Fujitsu MB86A16 DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 3000,
diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c
index 0f867a5055fb..fade566927c3 100644
--- a/drivers/media/dvb/frontends/mb86a20s.c
+++ b/drivers/media/dvb/frontends/mb86a20s.c
@@ -61,244 +61,111 @@ static struct regdata mb86a20s_init[] = {
{ 0x70, 0xff },
{ 0x08, 0x01 },
{ 0x09, 0x3e },
- { 0x50, 0xd1 },
- { 0x51, 0x22 },
+ { 0x50, 0xd1 }, { 0x51, 0x22 },
{ 0x39, 0x01 },
{ 0x71, 0x00 },
- { 0x28, 0x2a },
- { 0x29, 0x00 },
- { 0x2a, 0xff },
- { 0x2b, 0x80 },
- { 0x28, 0x20 },
- { 0x29, 0x33 },
- { 0x2a, 0xdf },
- { 0x2b, 0xa9 },
+ { 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 },
+ { 0x28, 0x20 }, { 0x29, 0x33 }, { 0x2a, 0xdf }, { 0x2b, 0xa9 },
+ { 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 },
{ 0x3b, 0x21 },
{ 0x3c, 0x3a },
{ 0x01, 0x0d },
- { 0x04, 0x08 },
- { 0x05, 0x05 },
- { 0x04, 0x0e },
- { 0x05, 0x00 },
- { 0x04, 0x0f },
- { 0x05, 0x14 },
- { 0x04, 0x0b },
- { 0x05, 0x8c },
- { 0x04, 0x00 },
- { 0x05, 0x00 },
- { 0x04, 0x01 },
- { 0x05, 0x07 },
- { 0x04, 0x02 },
- { 0x05, 0x0f },
- { 0x04, 0x03 },
- { 0x05, 0xa0 },
- { 0x04, 0x09 },
- { 0x05, 0x00 },
- { 0x04, 0x0a },
- { 0x05, 0xff },
- { 0x04, 0x27 },
- { 0x05, 0x64 },
- { 0x04, 0x28 },
- { 0x05, 0x00 },
- { 0x04, 0x1e },
- { 0x05, 0xff },
- { 0x04, 0x29 },
- { 0x05, 0x0a },
- { 0x04, 0x32 },
- { 0x05, 0x0a },
- { 0x04, 0x14 },
- { 0x05, 0x02 },
- { 0x04, 0x04 },
- { 0x05, 0x00 },
- { 0x04, 0x05 },
- { 0x05, 0x22 },
- { 0x04, 0x06 },
- { 0x05, 0x0e },
- { 0x04, 0x07 },
- { 0x05, 0xd8 },
- { 0x04, 0x12 },
- { 0x05, 0x00 },
- { 0x04, 0x13 },
- { 0x05, 0xff },
+ { 0x04, 0x08 }, { 0x05, 0x05 },
+ { 0x04, 0x0e }, { 0x05, 0x00 },
+ { 0x04, 0x0f }, { 0x05, 0x14 },
+ { 0x04, 0x0b }, { 0x05, 0x8c },
+ { 0x04, 0x00 }, { 0x05, 0x00 },
+ { 0x04, 0x01 }, { 0x05, 0x07 },
+ { 0x04, 0x02 }, { 0x05, 0x0f },
+ { 0x04, 0x03 }, { 0x05, 0xa0 },
+ { 0x04, 0x09 }, { 0x05, 0x00 },
+ { 0x04, 0x0a }, { 0x05, 0xff },
+ { 0x04, 0x27 }, { 0x05, 0x64 },
+ { 0x04, 0x28 }, { 0x05, 0x00 },
+ { 0x04, 0x1e }, { 0x05, 0xff },
+ { 0x04, 0x29 }, { 0x05, 0x0a },
+ { 0x04, 0x32 }, { 0x05, 0x0a },
+ { 0x04, 0x14 }, { 0x05, 0x02 },
+ { 0x04, 0x04 }, { 0x05, 0x00 },
+ { 0x04, 0x05 }, { 0x05, 0x22 },
+ { 0x04, 0x06 }, { 0x05, 0x0e },
+ { 0x04, 0x07 }, { 0x05, 0xd8 },
+ { 0x04, 0x12 }, { 0x05, 0x00 },
+ { 0x04, 0x13 }, { 0x05, 0xff },
+ { 0x04, 0x15 }, { 0x05, 0x4e },
+ { 0x04, 0x16 }, { 0x05, 0x20 },
{ 0x52, 0x01 },
- { 0x50, 0xa7 },
- { 0x51, 0x00 },
- { 0x50, 0xa8 },
- { 0x51, 0xff },
- { 0x50, 0xa9 },
- { 0x51, 0xff },
- { 0x50, 0xaa },
- { 0x51, 0x00 },
- { 0x50, 0xab },
- { 0x51, 0xff },
- { 0x50, 0xac },
- { 0x51, 0xff },
- { 0x50, 0xad },
- { 0x51, 0x00 },
- { 0x50, 0xae },
- { 0x51, 0xff },
- { 0x50, 0xaf },
- { 0x51, 0xff },
+ { 0x50, 0xa7 }, { 0x51, 0xff },
+ { 0x50, 0xa8 }, { 0x51, 0xff },
+ { 0x50, 0xa9 }, { 0x51, 0xff },
+ { 0x50, 0xaa }, { 0x51, 0xff },
+ { 0x50, 0xab }, { 0x51, 0xff },
+ { 0x50, 0xac }, { 0x51, 0xff },
+ { 0x50, 0xad }, { 0x51, 0xff },
+ { 0x50, 0xae }, { 0x51, 0xff },
+ { 0x50, 0xaf }, { 0x51, 0xff },
{ 0x5e, 0x07 },
- { 0x50, 0xdc },
- { 0x51, 0x01 },
- { 0x50, 0xdd },
- { 0x51, 0xf4 },
- { 0x50, 0xde },
- { 0x51, 0x01 },
- { 0x50, 0xdf },
- { 0x51, 0xf4 },
- { 0x50, 0xe0 },
- { 0x51, 0x01 },
- { 0x50, 0xe1 },
- { 0x51, 0xf4 },
- { 0x50, 0xb0 },
- { 0x51, 0x07 },
- { 0x50, 0xb2 },
- { 0x51, 0xff },
- { 0x50, 0xb3 },
- { 0x51, 0xff },
- { 0x50, 0xb4 },
- { 0x51, 0xff },
- { 0x50, 0xb5 },
- { 0x51, 0xff },
- { 0x50, 0xb6 },
- { 0x51, 0xff },
- { 0x50, 0xb7 },
- { 0x51, 0xff },
- { 0x50, 0x50 },
- { 0x51, 0x02 },
- { 0x50, 0x51 },
- { 0x51, 0x04 },
+ { 0x50, 0xdc }, { 0x51, 0x01 },
+ { 0x50, 0xdd }, { 0x51, 0xf4 },
+ { 0x50, 0xde }, { 0x51, 0x01 },
+ { 0x50, 0xdf }, { 0x51, 0xf4 },
+ { 0x50, 0xe0 }, { 0x51, 0x01 },
+ { 0x50, 0xe1 }, { 0x51, 0xf4 },
+ { 0x50, 0xb0 }, { 0x51, 0x07 },
+ { 0x50, 0xb2 }, { 0x51, 0xff },
+ { 0x50, 0xb3 }, { 0x51, 0xff },
+ { 0x50, 0xb4 }, { 0x51, 0xff },
+ { 0x50, 0xb5 }, { 0x51, 0xff },
+ { 0x50, 0xb6 }, { 0x51, 0xff },
+ { 0x50, 0xb7 }, { 0x51, 0xff },
+ { 0x50, 0x50 }, { 0x51, 0x02 },
+ { 0x50, 0x51 }, { 0x51, 0x04 },
{ 0x45, 0x04 },
{ 0x48, 0x04 },
- { 0x50, 0xd5 },
- { 0x51, 0x01 }, /* Serial */
- { 0x50, 0xd6 },
- { 0x51, 0x1f },
- { 0x50, 0xd2 },
- { 0x51, 0x03 },
- { 0x50, 0xd7 },
- { 0x51, 0x3f },
+ { 0x50, 0xd5 }, { 0x51, 0x01 }, /* Serial */
+ { 0x50, 0xd6 }, { 0x51, 0x1f },
+ { 0x50, 0xd2 }, { 0x51, 0x03 },
+ { 0x50, 0xd7 }, { 0x51, 0x3f },
+ { 0x28, 0x74 }, { 0x29, 0x00 }, { 0x28, 0x74 }, { 0x29, 0x40 },
+ { 0x28, 0x46 }, { 0x29, 0x2c }, { 0x28, 0x46 }, { 0x29, 0x0c },
+ { 0x04, 0x40 }, { 0x05, 0x01 },
+ { 0x28, 0x00 }, { 0x29, 0x10 },
+ { 0x28, 0x05 }, { 0x29, 0x02 },
{ 0x1c, 0x01 },
- { 0x28, 0x06 },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x03 },
- { 0x28, 0x07 },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x0d },
- { 0x28, 0x08 },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x02 },
- { 0x28, 0x09 },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x01 },
- { 0x28, 0x0a },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x21 },
- { 0x28, 0x0b },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x29 },
- { 0x28, 0x0c },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x16 },
- { 0x28, 0x0d },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x31 },
- { 0x28, 0x0e },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x0e },
- { 0x28, 0x0f },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x4e },
- { 0x28, 0x10 },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x46 },
- { 0x28, 0x11 },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x0f },
- { 0x28, 0x12 },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x56 },
- { 0x28, 0x13 },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x35 },
- { 0x28, 0x14 },
- { 0x29, 0x00 },
- { 0x2a, 0x01 },
- { 0x2b, 0xbe },
- { 0x28, 0x15 },
- { 0x29, 0x00 },
- { 0x2a, 0x01 },
- { 0x2b, 0x84 },
- { 0x28, 0x16 },
- { 0x29, 0x00 },
- { 0x2a, 0x03 },
- { 0x2b, 0xee },
- { 0x28, 0x17 },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x98 },
- { 0x28, 0x18 },
- { 0x29, 0x00 },
- { 0x2a, 0x00 },
- { 0x2b, 0x9f },
- { 0x28, 0x19 },
- { 0x29, 0x00 },
- { 0x2a, 0x07 },
- { 0x2b, 0xb2 },
- { 0x28, 0x1a },
- { 0x29, 0x00 },
- { 0x2a, 0x06 },
- { 0x2b, 0xc2 },
- { 0x28, 0x1b },
- { 0x29, 0x00 },
- { 0x2a, 0x07 },
- { 0x2b, 0x4a },
- { 0x28, 0x1c },
- { 0x29, 0x00 },
- { 0x2a, 0x01 },
- { 0x2b, 0xbc },
- { 0x28, 0x1d },
- { 0x29, 0x00 },
- { 0x2a, 0x04 },
- { 0x2b, 0xba },
- { 0x28, 0x1e },
- { 0x29, 0x00 },
- { 0x2a, 0x06 },
- { 0x2b, 0x14 },
- { 0x50, 0x1e },
- { 0x51, 0x5d },
- { 0x50, 0x22 },
- { 0x51, 0x00 },
- { 0x50, 0x23 },
- { 0x51, 0xc8 },
- { 0x50, 0x24 },
- { 0x51, 0x00 },
- { 0x50, 0x25 },
- { 0x51, 0xf0 },
- { 0x50, 0x26 },
- { 0x51, 0x00 },
- { 0x50, 0x27 },
- { 0x51, 0xc3 },
- { 0x50, 0x39 },
- { 0x51, 0x02 },
- { 0x50, 0xd5 },
- { 0x51, 0x01 },
+ { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 },
+ { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d },
+ { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 },
+ { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 },
+ { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 },
+ { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 },
+ { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 },
+ { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 },
+ { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e },
+ { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e },
+ { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 },
+ { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f },
+ { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 },
+ { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 },
+ { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe },
+ { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 },
+ { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee },
+ { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 },
+ { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f },
+ { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 },
+ { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 },
+ { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a },
+ { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc },
+ { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba },
+ { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 },
+ { 0x50, 0x1e }, { 0x51, 0x5d },
+ { 0x50, 0x22 }, { 0x51, 0x00 },
+ { 0x50, 0x23 }, { 0x51, 0xc8 },
+ { 0x50, 0x24 }, { 0x51, 0x00 },
+ { 0x50, 0x25 }, { 0x51, 0xf0 },
+ { 0x50, 0x26 }, { 0x51, 0x00 },
+ { 0x50, 0x27 }, { 0x51, 0xc3 },
+ { 0x50, 0x39 }, { 0x51, 0x02 },
+ { 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 },
{ 0xd0, 0x00 },
};
@@ -485,18 +352,23 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
return 0;
}
-static int mb86a20s_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int mb86a20s_set_frontend(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
int rc;
+#if 0
+ /*
+ * FIXME: Properly implement the set frontend properties
+ */
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+#endif
dprintk("\n");
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
dprintk("Calling tuner set parameters\n");
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
/*
* Make it more reliable: if, for some reason, the initial
@@ -520,22 +392,212 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe,
return rc;
}
-static int mb86a20s_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int mb86a20s_get_modulation(struct mb86a20s_state *state,
+ unsigned layer)
+{
+ int rc;
+ static unsigned char reg[] = {
+ [0] = 0x86, /* Layer A */
+ [1] = 0x8a, /* Layer B */
+ [2] = 0x8e, /* Layer C */
+ };
+
+ if (layer >= ARRAY_SIZE(reg))
+ return -EINVAL;
+ rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x6e);
+ if (rc < 0)
+ return rc;
+ switch ((rc & 0x70) >> 4) {
+ case 0:
+ return DQPSK;
+ case 1:
+ return QPSK;
+ case 2:
+ return QAM_16;
+ case 3:
+ return QAM_64;
+ default:
+ return QAM_AUTO;
+ }
+}
+
+static int mb86a20s_get_fec(struct mb86a20s_state *state,
+ unsigned layer)
{
+ int rc;
- /* FIXME: For now, it does nothing */
+ static unsigned char reg[] = {
+ [0] = 0x87, /* Layer A */
+ [1] = 0x8b, /* Layer B */
+ [2] = 0x8f, /* Layer C */
+ };
- fe->dtv_property_cache.bandwidth_hz = 6000000;
- fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
- fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
- fe->dtv_property_cache.isdbt_partial_reception = 0;
+ if (layer >= ARRAY_SIZE(reg))
+ return -EINVAL;
+ rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x6e);
+ if (rc < 0)
+ return rc;
+ switch (rc) {
+ case 0:
+ return FEC_1_2;
+ case 1:
+ return FEC_2_3;
+ case 2:
+ return FEC_3_4;
+ case 3:
+ return FEC_5_6;
+ case 4:
+ return FEC_7_8;
+ default:
+ return FEC_AUTO;
+ }
+}
+
+static int mb86a20s_get_interleaving(struct mb86a20s_state *state,
+ unsigned layer)
+{
+ int rc;
+
+ static unsigned char reg[] = {
+ [0] = 0x88, /* Layer A */
+ [1] = 0x8c, /* Layer B */
+ [2] = 0x90, /* Layer C */
+ };
+
+ if (layer >= ARRAY_SIZE(reg))
+ return -EINVAL;
+ rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x6e);
+ if (rc < 0)
+ return rc;
+ if (rc > 3)
+ return -EINVAL; /* Not used */
+ return rc;
+}
+
+static int mb86a20s_get_segment_count(struct mb86a20s_state *state,
+ unsigned layer)
+{
+ int rc, count;
+
+ static unsigned char reg[] = {
+ [0] = 0x89, /* Layer A */
+ [1] = 0x8d, /* Layer B */
+ [2] = 0x91, /* Layer C */
+ };
+
+ if (layer >= ARRAY_SIZE(reg))
+ return -EINVAL;
+ rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x6e);
+ if (rc < 0)
+ return rc;
+ count = (rc >> 4) & 0x0f;
+
+ return count;
+}
+
+static int mb86a20s_get_frontend(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ int i, rc;
+
+ /* Fixed parameters */
+ p->delivery_system = SYS_ISDBT;
+ p->bandwidth_hz = 6000000;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ /* Check for partial reception */
+ rc = mb86a20s_writereg(state, 0x6d, 0x85);
+ if (rc >= 0)
+ rc = mb86a20s_readreg(state, 0x6e);
+ if (rc >= 0)
+ p->isdbt_partial_reception = (rc & 0x10) ? 1 : 0;
+
+ /* Get per-layer data */
+ p->isdbt_layer_enabled = 0;
+ for (i = 0; i < 3; i++) {
+ rc = mb86a20s_get_segment_count(state, i);
+ if (rc >= 0 && rc < 14)
+ p->layer[i].segment_count = rc;
+ if (rc == 0x0f)
+ continue;
+ p->isdbt_layer_enabled |= 1 << i;
+ rc = mb86a20s_get_modulation(state, i);
+ if (rc >= 0)
+ p->layer[i].modulation = rc;
+ rc = mb86a20s_get_fec(state, i);
+ if (rc >= 0)
+ p->layer[i].fec = rc;
+ rc = mb86a20s_get_interleaving(state, i);
+ if (rc >= 0)
+ p->layer[i].interleaving = rc;
+ }
+
+ p->isdbt_sb_mode = 0;
+ rc = mb86a20s_writereg(state, 0x6d, 0x84);
+ if ((rc >= 0) && ((rc & 0x60) == 0x20)) {
+ p->isdbt_sb_mode = 1;
+ /* At least, one segment should exist */
+ if (!p->isdbt_sb_segment_count)
+ p->isdbt_sb_segment_count = 1;
+ } else
+ p->isdbt_sb_segment_count = 0;
+
+ /* Get transmission mode and guard interval */
+ p->transmission_mode = TRANSMISSION_MODE_AUTO;
+ p->guard_interval = GUARD_INTERVAL_AUTO;
+ rc = mb86a20s_readreg(state, 0x07);
+ if (rc >= 0) {
+ if ((rc & 0x60) == 0x20) {
+ switch (rc & 0x0c >> 2) {
+ case 0:
+ p->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ p->transmission_mode = TRANSMISSION_MODE_4K;
+ break;
+ case 2:
+ p->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ }
+ }
+ if (!(rc & 0x10)) {
+ switch (rc & 0x3) {
+ case 0:
+ p->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ case 1:
+ p->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 2:
+ p->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ }
+ }
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
return 0;
}
static int mb86a20s_tune(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
+ bool re_tune,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status)
@@ -544,8 +606,8 @@ static int mb86a20s_tune(struct dvb_frontend *fe,
dprintk("\n");
- if (params != NULL)
- rc = mb86a20s_set_frontend(fe, params);
+ if (re_tune)
+ rc = mb86a20s_set_frontend(fe);
if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
mb86a20s_read_status(fe, status);
@@ -608,10 +670,10 @@ error:
EXPORT_SYMBOL(mb86a20s_attach);
static struct dvb_frontend_ops mb86a20s_ops = {
+ .delsys = { SYS_ISDBT },
/* Use dib8000 values per default */
.info = {
.name = "Fujitsu mb86A20s",
- .type = FE_OFDM,
.caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 83e6f1a1b700..e20bf13aa860 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -531,9 +531,9 @@ static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
return 0;
}
-static int mt312_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int mt312_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mt312_state *state = fe->demodulator_priv;
int ret;
u8 buf[5], config_val;
@@ -553,16 +553,16 @@ static int mt312_set_frontend(struct dvb_frontend *fe,
|| (p->inversion > INVERSION_ON))
return -EINVAL;
- if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min)
- || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
+ if ((p->symbol_rate < fe->ops.info.symbol_rate_min)
+ || (p->symbol_rate > fe->ops.info.symbol_rate_max))
return -EINVAL;
- if ((p->u.qpsk.fec_inner < FEC_NONE)
- || (p->u.qpsk.fec_inner > FEC_AUTO))
+ if ((p->fec_inner < FEC_NONE)
+ || (p->fec_inner > FEC_AUTO))
return -EINVAL;
- if ((p->u.qpsk.fec_inner == FEC_4_5)
- || (p->u.qpsk.fec_inner == FEC_8_9))
+ if ((p->fec_inner == FEC_4_5)
+ || (p->fec_inner == FEC_8_9))
return -EINVAL;
switch (state->id) {
@@ -574,7 +574,7 @@ static int mt312_set_frontend(struct dvb_frontend *fe,
ret = mt312_readreg(state, CONFIG, &config_val);
if (ret < 0)
return ret;
- if (p->u.qpsk.symbol_rate >= 30000000) {
+ if (p->symbol_rate >= 30000000) {
/* Note that 30MS/s should use 90MHz */
if (state->freq_mult == 6) {
/* We are running 60MHz */
@@ -603,25 +603,25 @@ static int mt312_set_frontend(struct dvb_frontend *fe,
}
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
/* sr = (u16)(sr * 256.0 / 1000000.0) */
- sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
+ sr = mt312_div(p->symbol_rate * 4, 15625);
/* SYM_RATE */
buf[0] = (sr >> 8) & 0x3f;
buf[1] = (sr >> 0) & 0xff;
/* VIT_MODE */
- buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner];
+ buf[2] = inv_tab[p->inversion] | fec_tab[p->fec_inner];
/* QPSK_CTRL */
buf[3] = 0x40; /* swap I and Q before QPSK demodulation */
- if (p->u.qpsk.symbol_rate < 10000000)
+ if (p->symbol_rate < 10000000)
buf[3] |= 0x04; /* use afc mode */
/* GO */
@@ -636,9 +636,9 @@ static int mt312_set_frontend(struct dvb_frontend *fe,
return 0;
}
-static int mt312_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int mt312_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mt312_state *state = fe->demodulator_priv;
int ret;
@@ -646,11 +646,11 @@ static int mt312_get_frontend(struct dvb_frontend *fe,
if (ret < 0)
return ret;
- ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate);
+ ret = mt312_get_symbol_rate(state, &p->symbol_rate);
if (ret < 0)
return ret;
- ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner);
+ ret = mt312_get_code_rate(state, &p->fec_inner);
if (ret < 0)
return ret;
@@ -738,10 +738,9 @@ static void mt312_release(struct dvb_frontend *fe)
#define MT312_SYS_CLK 90000000UL /* 90 MHz */
static struct dvb_frontend_ops mt312_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "Zarlink ???? DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
/* FIXME: adjust freq to real used xtal */
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index 319672f8e1a7..2c3b50e828d7 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -111,20 +111,20 @@ static int mt352_sleep(struct dvb_frontend* fe)
}
static void mt352_calc_nominal_rate(struct mt352_state* state,
- enum fe_bandwidth bandwidth,
+ u32 bandwidth,
unsigned char *buf)
{
u32 adc_clock = 20480; /* 20.340 MHz */
u32 bw,value;
switch (bandwidth) {
- case BANDWIDTH_6_MHZ:
+ case 6000000:
bw = 6;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
bw = 7;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
default:
bw = 8;
break;
@@ -166,15 +166,14 @@ static void mt352_calc_input_freq(struct mt352_state* state,
buf[1] = lsb(value);
}
-static int mt352_set_parameters(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *param)
+static int mt352_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *op = &fe->dtv_property_cache;
struct mt352_state* state = fe->demodulator_priv;
unsigned char buf[13];
static unsigned char tuner_go[] = { 0x5d, 0x01 };
static unsigned char fsm_go[] = { 0x5e, 0x01 };
unsigned int tps = 0;
- struct dvb_ofdm_parameters *op = &param->u.ofdm;
switch (op->code_rate_HP) {
case FEC_2_3:
@@ -213,14 +212,14 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
case FEC_AUTO:
break;
case FEC_NONE:
- if (op->hierarchy_information == HIERARCHY_AUTO ||
- op->hierarchy_information == HIERARCHY_NONE)
+ if (op->hierarchy == HIERARCHY_AUTO ||
+ op->hierarchy == HIERARCHY_NONE)
break;
default:
return -EINVAL;
}
- switch (op->constellation) {
+ switch (op->modulation) {
case QPSK:
break;
case QAM_AUTO:
@@ -262,7 +261,7 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
return -EINVAL;
}
- switch (op->hierarchy_information) {
+ switch (op->hierarchy) {
case HIERARCHY_AUTO:
case HIERARCHY_NONE:
break;
@@ -288,12 +287,12 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
buf[3] = 0x50; // old
// buf[3] = 0xf4; // pinnacle
- mt352_calc_nominal_rate(state, op->bandwidth, buf+4);
+ mt352_calc_nominal_rate(state, op->bandwidth_hz, buf+4);
mt352_calc_input_freq(state, buf+6);
if (state->config.no_tuner) {
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, param);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -302,7 +301,7 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
_mt352_write(fe, fsm_go, 2);
} else {
if (fe->ops.tuner_ops.calc_regs) {
- fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
+ fe->ops.tuner_ops.calc_regs(fe, buf+8, 5);
buf[8] <<= 1;
_mt352_write(fe, buf, sizeof(buf));
_mt352_write(fe, tuner_go, 2);
@@ -312,14 +311,13 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
return 0;
}
-static int mt352_get_parameters(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *param)
+static int mt352_get_parameters(struct dvb_frontend* fe)
{
+ struct dtv_frontend_properties *op = &fe->dtv_property_cache;
struct mt352_state* state = fe->demodulator_priv;
u16 tps;
u16 div;
u8 trl;
- struct dvb_ofdm_parameters *op = &param->u.ofdm;
static const u8 tps_fec_to_api[8] =
{
FEC_1_2,
@@ -348,16 +346,16 @@ static int mt352_get_parameters(struct dvb_frontend* fe,
switch ( (tps >> 13) & 3)
{
case 0:
- op->constellation = QPSK;
+ op->modulation = QPSK;
break;
case 1:
- op->constellation = QAM_16;
+ op->modulation = QAM_16;
break;
case 2:
- op->constellation = QAM_64;
+ op->modulation = QAM_64;
break;
default:
- op->constellation = QAM_AUTO;
+ op->modulation = QAM_AUTO;
break;
}
@@ -385,36 +383,36 @@ static int mt352_get_parameters(struct dvb_frontend* fe,
switch ( (tps >> 10) & 7)
{
case 0:
- op->hierarchy_information = HIERARCHY_NONE;
+ op->hierarchy = HIERARCHY_NONE;
break;
case 1:
- op->hierarchy_information = HIERARCHY_1;
+ op->hierarchy = HIERARCHY_1;
break;
case 2:
- op->hierarchy_information = HIERARCHY_2;
+ op->hierarchy = HIERARCHY_2;
break;
case 3:
- op->hierarchy_information = HIERARCHY_4;
+ op->hierarchy = HIERARCHY_4;
break;
default:
- op->hierarchy_information = HIERARCHY_AUTO;
+ op->hierarchy = HIERARCHY_AUTO;
break;
}
- param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000;
+ op->frequency = (500 * (div - IF_FREQUENCYx6)) / 3 * 1000;
if (trl == 0x72)
- op->bandwidth = BANDWIDTH_8_MHZ;
+ op->bandwidth_hz = 8000000;
else if (trl == 0x64)
- op->bandwidth = BANDWIDTH_7_MHZ;
+ op->bandwidth_hz = 7000000;
else
- op->bandwidth = BANDWIDTH_6_MHZ;
+ op->bandwidth_hz = 6000000;
if (mt352_read_register(state, STATUS_2) & 0x02)
- param->inversion = INVERSION_OFF;
+ op->inversion = INVERSION_OFF;
else
- param->inversion = INVERSION_ON;
+ op->inversion = INVERSION_ON;
return 0;
}
@@ -569,10 +567,9 @@ error:
}
static struct dvb_frontend_ops mt352_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "Zarlink MT352 DVB-T",
- .type = FE_OFDM,
.frequency_min = 174000000,
.frequency_max = 862000000,
.frequency_stepsize = 166667,
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index eac20650499f..49ca78d883b1 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -528,9 +528,9 @@ static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware
return 0;
};
-static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
- struct dvb_frontend_parameters *p)
+static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct nxt200x_state* state = fe->demodulator_priv;
u8 buf[5];
@@ -546,7 +546,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
}
/* set additional params */
- switch (p->u.vsb.modulation) {
+ switch (p->modulation) {
case QAM_64:
case QAM_256:
/* Set punctured clock for QAM */
@@ -566,7 +566,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
if (fe->ops.tuner_ops.calc_regs) {
/* get tuning information */
- fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+ fe->ops.tuner_ops.calc_regs(fe, buf, 5);
/* write frequency information */
nxt200x_writetuner(state, buf);
@@ -576,7 +576,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
nxt200x_agc_reset(state);
/* set target power level */
- switch (p->u.vsb.modulation) {
+ switch (p->modulation) {
case QAM_64:
case QAM_256:
buf[0] = 0x74;
@@ -620,7 +620,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
}
/* write sdmx input */
- switch (p->u.vsb.modulation) {
+ switch (p->modulation) {
case QAM_64:
buf[0] = 0x68;
break;
@@ -714,7 +714,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
}
/* write agc ucgp0 */
- switch (p->u.vsb.modulation) {
+ switch (p->modulation) {
case QAM_64:
buf[0] = 0x02;
break;
@@ -1203,10 +1203,9 @@ error:
}
static struct dvb_frontend_ops nxt200x_ops = {
-
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name = "Nextwave NXT200X VSB/QAM frontend",
- .type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 860000000,
.frequency_stepsize = 166666, /* stepsize is just a guess */
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
index 6599b8fea9e9..90ae6c72c0e3 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -81,22 +81,21 @@ static void nxt6000_reset(struct nxt6000_state* state)
nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT);
}
-static int nxt6000_set_bandwidth(struct nxt6000_state* state, fe_bandwidth_t bandwidth)
+static int nxt6000_set_bandwidth(struct nxt6000_state *state, u32 bandwidth)
{
u16 nominal_rate;
int result;
switch (bandwidth) {
-
- case BANDWIDTH_6_MHZ:
+ case 6000000:
nominal_rate = 0x55B7;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
nominal_rate = 0x6400;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
nominal_rate = 0x7249;
break;
@@ -457,23 +456,31 @@ static int nxt6000_init(struct dvb_frontend* fe)
return 0;
}
-static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
+static int nxt6000_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct nxt6000_state* state = fe->demodulator_priv;
int result;
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, param);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
+ result = nxt6000_set_bandwidth(state, p->bandwidth_hz);
+ if (result < 0)
return result;
- if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0)
+
+ result = nxt6000_set_guard_interval(state, p->guard_interval);
+ if (result < 0)
return result;
- if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0)
+
+ result = nxt6000_set_transmission_mode(state, p->transmission_mode);
+ if (result < 0)
return result;
- if ((result = nxt6000_set_inversion(state, param->inversion)) < 0)
+
+ result = nxt6000_set_inversion(state, p->inversion);
+ if (result < 0)
return result;
msleep(500);
@@ -566,10 +573,9 @@ error:
}
static struct dvb_frontend_ops nxt6000_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "NxtWave NXT6000 DVB-T",
- .type = FE_OFDM,
.frequency_min = 0,
.frequency_max = 863250000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 38e67accb8c3..5ef921823c15 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -306,9 +306,9 @@ static int modulation_fw_class(fe_modulation_t modulation)
}
}
-static int or51132_set_parameters(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *param)
+static int or51132_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
int ret;
struct or51132_state* state = fe->demodulator_priv;
const struct firmware *fw;
@@ -317,8 +317,8 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
/* Upload new firmware only if we need a different one */
if (modulation_fw_class(state->current_modulation) !=
- modulation_fw_class(param->u.vsb.modulation)) {
- switch(modulation_fw_class(param->u.vsb.modulation)) {
+ modulation_fw_class(p->modulation)) {
+ switch (modulation_fw_class(p->modulation)) {
case MOD_FWCLASS_VSB:
dprintk("set_parameters VSB MODE\n");
fwname = OR51132_VSB_FIRMWARE;
@@ -335,7 +335,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
break;
default:
printk("or51132: Modulation type(%d) UNSUPPORTED\n",
- param->u.vsb.modulation);
+ p->modulation);
return -1;
}
printk("or51132: Waiting for firmware upload(%s)...\n",
@@ -357,13 +357,13 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
state->config->set_ts_params(fe, clock_mode);
}
/* Change only if we are actually changing the modulation */
- if (state->current_modulation != param->u.vsb.modulation) {
- state->current_modulation = param->u.vsb.modulation;
+ if (state->current_modulation != p->modulation) {
+ state->current_modulation = p->modulation;
or51132_setmode(fe);
}
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, param);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -371,13 +371,13 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
or51132_setmode(fe);
/* Update current frequency */
- state->current_frequency = param->frequency;
+ state->current_frequency = p->frequency;
return 0;
}
-static int or51132_get_parameters(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *param)
+static int or51132_get_parameters(struct dvb_frontend* fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct or51132_state* state = fe->demodulator_priv;
int status;
int retry = 1;
@@ -389,21 +389,28 @@ start:
return -EREMOTEIO;
}
switch(status&0xff) {
- case 0x06: param->u.vsb.modulation = VSB_8; break;
- case 0x43: param->u.vsb.modulation = QAM_64; break;
- case 0x45: param->u.vsb.modulation = QAM_256; break;
- default:
- if (retry--) goto start;
- printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
- status&0xff);
- return -EREMOTEIO;
+ case 0x06:
+ p->modulation = VSB_8;
+ break;
+ case 0x43:
+ p->modulation = QAM_64;
+ break;
+ case 0x45:
+ p->modulation = QAM_256;
+ break;
+ default:
+ if (retry--)
+ goto start;
+ printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
+ status&0xff);
+ return -EREMOTEIO;
}
/* FIXME: Read frequency from frontend, take AFC into account */
- param->frequency = state->current_frequency;
+ p->frequency = state->current_frequency;
/* FIXME: How to read inversion setting? Receiver 6 register? */
- param->inversion = INVERSION_AUTO;
+ p->inversion = INVERSION_AUTO;
return 0;
}
@@ -579,10 +586,9 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
}
static struct dvb_frontend_ops or51132_ops = {
-
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name = "Oren OR51132 VSB/QAM Frontend",
- .type = FE_ATSC,
.frequency_min = 44000000,
.frequency_max = 958000000,
.frequency_stepsize = 166666,
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index c709ce6771c8..c625b57b4333 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -218,15 +218,15 @@ static int or51211_setmode(struct dvb_frontend* fe, int mode)
return 0;
}
-static int or51211_set_parameters(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *param)
+static int or51211_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct or51211_state* state = fe->demodulator_priv;
/* Change only if we are actually changing the channel */
- if (state->current_frequency != param->frequency) {
+ if (state->current_frequency != p->frequency) {
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, param);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -234,7 +234,7 @@ static int or51211_set_parameters(struct dvb_frontend* fe,
or51211_setmode(fe,0);
/* Update current frequency */
- state->current_frequency = param->frequency;
+ state->current_frequency = p->frequency;
}
return 0;
}
@@ -544,10 +544,9 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
}
static struct dvb_frontend_ops or51211_ops = {
-
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name = "Oren OR51211 VSB Frontend",
- .type = FE_ATSC,
.frequency_min = 44000000,
.frequency_max = 958000000,
.frequency_stepsize = 166666,
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c
new file mode 100644
index 000000000000..45196c5b0736
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2830.c
@@ -0,0 +1,562 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+/*
+ * Driver implements own I2C-adapter for tuner I2C access. That's since chip
+ * have unusual I2C-gate control which closes gate automatically after each
+ * I2C transfer. Using own I2C adapter we can workaround that.
+ */
+
+#include "rtl2830_priv.h"
+
+int rtl2830_debug;
+module_param_named(debug, rtl2830_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+/* write multiple hardware registers */
+static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
+{
+ int ret;
+ u8 buf[1+len];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->cfg.i2c_addr,
+ .flags = 0,
+ .len = 1+len,
+ .buf = buf,
+ }
+ };
+
+ buf[0] = reg;
+ memcpy(&buf[1], val, len);
+
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
+
+/* read multiple hardware registers */
+static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
+{
+ int ret;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = priv->cfg.i2c_addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &reg,
+ }, {
+ .addr = priv->cfg.i2c_addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = val,
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret == 2) {
+ ret = 0;
+ } else {
+ warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
+
+/* write multiple registers */
+static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
+{
+ int ret;
+ u8 reg2 = (reg >> 0) & 0xff;
+ u8 page = (reg >> 8) & 0xff;
+
+ /* switch bank if needed */
+ if (page != priv->page) {
+ ret = rtl2830_wr(priv, 0x00, &page, 1);
+ if (ret)
+ return ret;
+
+ priv->page = page;
+ }
+
+ return rtl2830_wr(priv, reg2, val, len);
+}
+
+/* read multiple registers */
+static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
+{
+ int ret;
+ u8 reg2 = (reg >> 0) & 0xff;
+ u8 page = (reg >> 8) & 0xff;
+
+ /* switch bank if needed */
+ if (page != priv->page) {
+ ret = rtl2830_wr(priv, 0x00, &page, 1);
+ if (ret)
+ return ret;
+
+ priv->page = page;
+ }
+
+ return rtl2830_rd(priv, reg2, val, len);
+}
+
+#if 0 /* currently not used */
+/* write single register */
+static int rtl2830_wr_reg(struct rtl2830_priv *priv, u16 reg, u8 val)
+{
+ return rtl2830_wr_regs(priv, reg, &val, 1);
+}
+#endif
+
+/* read single register */
+static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val)
+{
+ return rtl2830_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ /* no need for read if whole reg is written */
+ if (mask != 0xff) {
+ ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
+ if (ret)
+ return ret;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ return rtl2830_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register with mask */
+int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask)
+{
+ int ret, i;
+ u8 tmp;
+
+ ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
+ if (ret)
+ return ret;
+
+ tmp &= mask;
+
+ /* find position of the first bit */
+ for (i = 0; i < 8; i++) {
+ if ((mask >> i) & 0x01)
+ break;
+ }
+ *val = tmp >> i;
+
+ return 0;
+}
+
+static int rtl2830_init(struct dvb_frontend *fe)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ int ret, i;
+ u64 num;
+ u8 buf[3], tmp;
+ u32 if_ctl;
+ struct rtl2830_reg_val_mask tab[] = {
+ { 0x00d, 0x01, 0x03 },
+ { 0x00d, 0x10, 0x10 },
+ { 0x104, 0x00, 0x1e },
+ { 0x105, 0x80, 0x80 },
+ { 0x110, 0x02, 0x03 },
+ { 0x110, 0x08, 0x0c },
+ { 0x17b, 0x00, 0x40 },
+ { 0x17d, 0x05, 0x0f },
+ { 0x17d, 0x50, 0xf0 },
+ { 0x18c, 0x08, 0x0f },
+ { 0x18d, 0x00, 0xc0 },
+ { 0x188, 0x05, 0x0f },
+ { 0x189, 0x00, 0xfc },
+ { 0x2d5, 0x02, 0x02 },
+ { 0x2f1, 0x02, 0x06 },
+ { 0x2f1, 0x20, 0xf8 },
+ { 0x16d, 0x00, 0x01 },
+ { 0x1a6, 0x00, 0x80 },
+ { 0x106, priv->cfg.vtop, 0x3f },
+ { 0x107, priv->cfg.krf, 0x3f },
+ { 0x112, 0x28, 0xff },
+ { 0x103, priv->cfg.agc_targ_val, 0xff },
+ { 0x00a, 0x02, 0x07 },
+ { 0x140, 0x0c, 0x3c },
+ { 0x140, 0x40, 0xc0 },
+ { 0x15b, 0x05, 0x07 },
+ { 0x15b, 0x28, 0x38 },
+ { 0x15c, 0x05, 0x07 },
+ { 0x15c, 0x28, 0x38 },
+ { 0x115, priv->cfg.spec_inv, 0x01 },
+ { 0x16f, 0x01, 0x07 },
+ { 0x170, 0x18, 0x38 },
+ { 0x172, 0x0f, 0x0f },
+ { 0x173, 0x08, 0x38 },
+ { 0x175, 0x01, 0x07 },
+ { 0x176, 0x00, 0xc0 },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+ tab[i].mask);
+ if (ret)
+ goto err;
+ }
+
+ ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2);
+ if (ret)
+ goto err;
+
+ ret = rtl2830_wr_regs(priv, 0x195,
+ "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
+ if (ret)
+ goto err;
+
+ num = priv->cfg.if_dvbt % priv->cfg.xtal;
+ num *= 0x400000;
+ num = div_u64(num, priv->cfg.xtal);
+ num = -num;
+ if_ctl = num & 0x3fffff;
+ dbg("%s: if_ctl=%08x", __func__, if_ctl);
+
+ ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */
+ if (ret)
+ goto err;
+
+ buf[0] = tmp << 6;
+ buf[0] = (if_ctl >> 16) & 0x3f;
+ buf[1] = (if_ctl >> 8) & 0xff;
+ buf[2] = (if_ctl >> 0) & 0xff;
+
+ ret = rtl2830_wr_regs(priv, 0x119, buf, 3);
+ if (ret)
+ goto err;
+
+ /* TODO: spec init */
+
+ /* soft reset */
+ ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04);
+ if (ret)
+ goto err;
+
+ ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04);
+ if (ret)
+ goto err;
+
+ priv->sleeping = false;
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int rtl2830_sleep(struct dvb_frontend *fe)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ priv->sleeping = true;
+ return 0;
+}
+
+int rtl2830_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 500;
+ s->step_size = fe->ops.info.frequency_stepsize * 2;
+ s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+
+ return 0;
+}
+
+static int rtl2830_set_frontend(struct dvb_frontend *fe)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i;
+ static u8 bw_params1[3][34] = {
+ {
+ 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41,
+ 0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a,
+ 0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82,
+ 0x03, 0x73, 0x03, 0xcf, /* 6 MHz */
+ }, {
+ 0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca,
+ 0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca,
+ 0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e,
+ 0x03, 0xd0, 0x04, 0x53, /* 7 MHz */
+ }, {
+ 0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0,
+ 0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a,
+ 0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f,
+ 0x04, 0x24, 0x04, 0xdb, /* 8 MHz */
+ },
+ };
+ static u8 bw_params2[3][6] = {
+ {0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30,}, /* 6 MHz */
+ {0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98,}, /* 7 MHz */
+ {0xae, 0xba, 0xf3, 0x26, 0x66, 0x64,}, /* 8 MHz */
+ };
+
+
+ dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
+ c->frequency, c->bandwidth_hz, c->inversion);
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe);
+
+ switch (c->bandwidth_hz) {
+ case 6000000:
+ i = 0;
+ break;
+ case 7000000:
+ i = 1;
+ break;
+ case 8000000:
+ i = 2;
+ break;
+ default:
+ dbg("invalid bandwidth");
+ return -EINVAL;
+ }
+
+ ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06);
+ if (ret)
+ goto err;
+
+ /* 1/2 split I2C write */
+ ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17);
+ if (ret)
+ goto err;
+
+ /* 2/2 split I2C write */
+ ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17);
+ if (ret)
+ goto err;
+
+ ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6);
+ if (ret)
+ goto err;
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 tmp;
+ *status = 0;
+
+ if (priv->sleeping)
+ return 0;
+
+ ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */
+ if (ret)
+ goto err;
+
+ if (tmp == 11) {
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ } else if (tmp == 10) {
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI;
+ }
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ *snr = 0;
+ return 0;
+}
+
+static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ *ber = 0;
+ return 0;
+}
+
+static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ *ucblocks = 0;
+ return 0;
+}
+
+static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ *strength = 0;
+ return 0;
+}
+
+static struct dvb_frontend_ops rtl2830_ops;
+
+static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msg[], int num)
+{
+ struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap);
+ int ret;
+
+ /* open i2c-gate */
+ ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08);
+ if (ret)
+ goto err;
+
+ ret = i2c_transfer(priv->i2c, msg, num);
+ if (ret < 0)
+ warn("tuner i2c failed=%d", ret);
+
+ return ret;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
+static struct i2c_algorithm rtl2830_tuner_i2c_algo = {
+ .master_xfer = rtl2830_tuner_i2c_xfer,
+ .functionality = rtl2830_tuner_i2c_func,
+};
+
+struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ return &priv->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter);
+
+static void rtl2830_release(struct dvb_frontend *fe)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+
+ i2c_del_adapter(&priv->tuner_i2c_adapter);
+ kfree(priv);
+}
+
+struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg,
+ struct i2c_adapter *i2c)
+{
+ struct rtl2830_priv *priv = NULL;
+ int ret = 0;
+ u8 tmp;
+
+ /* allocate memory for the internal state */
+ priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL);
+ if (priv == NULL)
+ goto err;
+
+ /* setup the priv */
+ priv->i2c = i2c;
+ memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config));
+
+ /* check if the demod is there */
+ ret = rtl2830_rd_reg(priv, 0x000, &tmp);
+ if (ret)
+ goto err;
+
+ /* create dvb_frontend */
+ memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops));
+ priv->fe.demodulator_priv = priv;
+
+ /* create tuner i2c adapter */
+ strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter",
+ sizeof(priv->tuner_i2c_adapter.name));
+ priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo;
+ priv->tuner_i2c_adapter.algo_data = NULL;
+ i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
+ if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
+ err("tuner I2C bus could not be initialized");
+ goto err;
+ }
+
+ priv->sleeping = true;
+
+ return &priv->fe;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ kfree(priv);
+ return NULL;
+}
+EXPORT_SYMBOL(rtl2830_attach);
+
+static struct dvb_frontend_ops rtl2830_ops = {
+ .delsys = { SYS_DVBT },
+ .info = {
+ .name = "Realtek RTL2830 (DVB-T)",
+ .caps = FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_MUTE_TS
+ },
+
+ .release = rtl2830_release,
+
+ .init = rtl2830_init,
+ .sleep = rtl2830_sleep,
+
+ .get_tune_settings = rtl2830_get_tune_settings,
+
+ .set_frontend = rtl2830_set_frontend,
+
+ .read_status = rtl2830_read_status,
+ .read_snr = rtl2830_read_snr,
+ .read_ber = rtl2830_read_ber,
+ .read_ucblocks = rtl2830_read_ucblocks,
+ .read_signal_strength = rtl2830_read_signal_strength,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/rtl2830.h b/drivers/media/dvb/frontends/rtl2830.h
new file mode 100644
index 000000000000..1c6ee91749c2
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2830.h
@@ -0,0 +1,97 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2830_H
+#define RTL2830_H
+
+#include <linux/dvb/frontend.h>
+
+struct rtl2830_config {
+ /*
+ * Demodulator I2C address.
+ */
+ u8 i2c_addr;
+
+ /*
+ * Xtal frequency.
+ * Hz
+ * 4000000, 16000000, 25000000, 28800000
+ */
+ u32 xtal;
+
+ /*
+ * TS output mode.
+ */
+ u8 ts_mode;
+
+ /*
+ * Spectrum inversion.
+ */
+ bool spec_inv;
+
+ /*
+ * IFs for all used modes.
+ * Hz
+ * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
+ */
+ u32 if_dvbt;
+
+ /*
+ */
+ u8 vtop;
+
+ /*
+ */
+ u8 krf;
+
+ /*
+ */
+ u8 agc_targ_val;
+};
+
+#if defined(CONFIG_DVB_RTL2830) || \
+ (defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE))
+extern struct dvb_frontend *rtl2830_attach(
+ const struct rtl2830_config *config,
+ struct i2c_adapter *i2c
+);
+
+extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
+ struct dvb_frontend *fe
+);
+#else
+static inline struct dvb_frontend *rtl2830_attach(
+ const struct rtl2830_config *config,
+ struct i2c_adapter *i2c
+)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+
+static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
+ struct dvb_frontend *fe
+)
+{
+ return NULL;
+}
+#endif
+
+#endif /* RTL2830_H */
diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h
new file mode 100644
index 000000000000..4a464761b5b8
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2830_priv.h
@@ -0,0 +1,57 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2830_PRIV_H
+#define RTL2830_PRIV_H
+
+#include "dvb_frontend.h"
+#include "rtl2830.h"
+
+#define LOG_PREFIX "rtl2830"
+
+#undef dbg
+#define dbg(f, arg...) \
+ if (rtl2830_debug) \
+ printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct rtl2830_priv {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend fe;
+ struct rtl2830_config cfg;
+ struct i2c_adapter tuner_i2c_adapter;
+
+ bool sleeping;
+
+ u8 page; /* active register page */
+};
+
+struct rtl2830_reg_val_mask {
+ u16 reg;
+ u8 val;
+ u8 mask;
+};
+
+#endif /* RTL2830_PRIV_H */
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index 0e2f61a8978f..f71b06221e14 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -631,9 +631,9 @@ static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe)
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1409_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int s5h1409_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(frequency=%d)\n", __func__, p->frequency);
@@ -642,12 +642,12 @@ static int s5h1409_set_frontend(struct dvb_frontend *fe,
state->current_frequency = p->frequency;
- s5h1409_enable_modulation(fe, p->u.vsb.modulation);
+ s5h1409_enable_modulation(fe, p->modulation);
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -879,7 +879,36 @@ static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr)
static int s5h1409_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
- return s5h1409_read_snr(fe, signal_strength);
+ /* borrowed from lgdt330x.c
+ *
+ * Calculate strength from SNR up to 35dB
+ * Even though the SNR can go higher than 35dB,
+ * there is some comfort factor in having a range of
+ * strong signals that can show at 100%
+ */
+ u16 snr;
+ u32 tmp;
+ int ret = s5h1409_read_snr(fe, &snr);
+
+ *signal_strength = 0;
+
+ if (0 == ret) {
+ /* The following calculation method was chosen
+ * purely for the sake of code re-use from the
+ * other demod drivers that use this method */
+
+ /* Convert from SNR in dB * 10 to 8.24 fixed-point */
+ tmp = (snr * ((1 << 24) / 10));
+
+ /* Convert from 8.24 fixed-point to
+ * scale the range 0 - 35*2^24 into 0 - 65535*/
+ if (tmp >= 8960 * 0x10000)
+ *signal_strength = 0xffff;
+ else
+ *signal_strength = tmp / 8960;
+ }
+
+ return ret;
}
static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
@@ -896,13 +925,13 @@ static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber)
return s5h1409_read_ucblocks(fe, ber);
}
-static int s5h1409_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int s5h1409_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s5h1409_state *state = fe->demodulator_priv;
p->frequency = state->current_frequency;
- p->u.vsb.modulation = state->current_modulation;
+ p->modulation = state->current_modulation;
return 0;
}
@@ -967,10 +996,9 @@ error:
EXPORT_SYMBOL(s5h1409_attach);
static struct dvb_frontend_ops s5h1409_ops = {
-
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name = "Samsung S5H1409 QAM/8VSB Frontend",
- .type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c
index d8adf1e32019..6cc4b7a9dd60 100644
--- a/drivers/media/dvb/frontends/s5h1411.c
+++ b/drivers/media/dvb/frontends/s5h1411.c
@@ -585,9 +585,9 @@ static int s5h1411_register_reset(struct dvb_frontend *fe)
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1411_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int s5h1411_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s5h1411_state *state = fe->demodulator_priv;
dprintk("%s(frequency=%d)\n", __func__, p->frequency);
@@ -596,13 +596,13 @@ static int s5h1411_set_frontend(struct dvb_frontend *fe,
state->current_frequency = p->frequency;
- s5h1411_enable_modulation(fe, p->u.vsb.modulation);
+ s5h1411_enable_modulation(fe, p->modulation);
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
@@ -794,7 +794,36 @@ static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr)
static int s5h1411_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
- return s5h1411_read_snr(fe, signal_strength);
+ /* borrowed from lgdt330x.c
+ *
+ * Calculate strength from SNR up to 35dB
+ * Even though the SNR can go higher than 35dB,
+ * there is some comfort factor in having a range of
+ * strong signals that can show at 100%
+ */
+ u16 snr;
+ u32 tmp;
+ int ret = s5h1411_read_snr(fe, &snr);
+
+ *signal_strength = 0;
+
+ if (0 == ret) {
+ /* The following calculation method was chosen
+ * purely for the sake of code re-use from the
+ * other demod drivers that use this method */
+
+ /* Convert from SNR in dB * 10 to 8.24 fixed-point */
+ tmp = (snr * ((1 << 24) / 10));
+
+ /* Convert from 8.24 fixed-point to
+ * scale the range 0 - 35*2^24 into 0 - 65535*/
+ if (tmp >= 8960 * 0x10000)
+ *signal_strength = 0xffff;
+ else
+ *signal_strength = tmp / 8960;
+ }
+
+ return ret;
}
static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
@@ -811,13 +840,13 @@ static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber)
return s5h1411_read_ucblocks(fe, ber);
}
-static int s5h1411_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int s5h1411_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s5h1411_state *state = fe->demodulator_priv;
p->frequency = state->current_frequency;
- p->u.vsb.modulation = state->current_modulation;
+ p->modulation = state->current_modulation;
return 0;
}
@@ -886,10 +915,9 @@ error:
EXPORT_SYMBOL(s5h1411_attach);
static struct dvb_frontend_ops s5h1411_ops = {
-
+ .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
.info = {
.name = "Samsung S5H1411 QAM/8VSB Frontend",
- .type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 3879d2e378aa..2322257c69ae 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -472,15 +472,15 @@ static void s5h1420_reset(struct s5h1420_state* state)
}
static void s5h1420_setsymbolrate(struct s5h1420_state* state,
- struct dvb_frontend_parameters *p)
+ struct dtv_frontend_properties *p)
{
u8 v;
u64 val;
dprintk("enter %s\n", __func__);
- val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24);
- if (p->u.qpsk.symbol_rate < 29000000)
+ val = ((u64) p->symbol_rate / 1000ULL) * (1ULL<<24);
+ if (p->symbol_rate < 29000000)
val *= 2;
do_div(val, (state->fclk / 1000));
@@ -543,7 +543,7 @@ static int s5h1420_getfreqoffset(struct s5h1420_state* state)
}
static void s5h1420_setfec_inversion(struct s5h1420_state* state,
- struct dvb_frontend_parameters *p)
+ struct dtv_frontend_properties *p)
{
u8 inversion = 0;
u8 vit08, vit09;
@@ -555,11 +555,11 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state,
else if (p->inversion == INVERSION_ON)
inversion = state->config->invert ? 0 : 0x08;
- if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
+ if ((p->fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
vit08 = 0x3f;
vit09 = 0;
} else {
- switch(p->u.qpsk.fec_inner) {
+ switch (p->fec_inner) {
case FEC_1_2:
vit08 = 0x01; vit09 = 0x10;
break;
@@ -628,9 +628,9 @@ static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state)
return INVERSION_OFF;
}
-static int s5h1420_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *p)
+static int s5h1420_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s5h1420_state* state = fe->demodulator_priv;
int frequency_delta;
struct dvb_frontend_tune_settings fesettings;
@@ -639,17 +639,16 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
dprintk("enter %s\n", __func__);
/* check if we should do a fast-tune */
- memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
s5h1420_get_tune_settings(fe, &fesettings);
frequency_delta = p->frequency - state->tunedfreq;
if ((frequency_delta > -fesettings.max_drift) &&
(frequency_delta < fesettings.max_drift) &&
(frequency_delta != 0) &&
- (state->fec_inner == p->u.qpsk.fec_inner) &&
- (state->symbol_rate == p->u.qpsk.symbol_rate)) {
+ (state->fec_inner == p->fec_inner) &&
+ (state->symbol_rate == p->symbol_rate)) {
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
if (fe->ops.tuner_ops.get_frequency) {
@@ -669,13 +668,13 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
s5h1420_reset(state);
/* set s5h1420 fclk PLL according to desired symbol rate */
- if (p->u.qpsk.symbol_rate > 33000000)
+ if (p->symbol_rate > 33000000)
state->fclk = 80000000;
- else if (p->u.qpsk.symbol_rate > 28500000)
+ else if (p->symbol_rate > 28500000)
state->fclk = 59000000;
- else if (p->u.qpsk.symbol_rate > 25000000)
+ else if (p->symbol_rate > 25000000)
state->fclk = 86000000;
- else if (p->u.qpsk.symbol_rate > 1900000)
+ else if (p->symbol_rate > 1900000)
state->fclk = 88000000;
else
state->fclk = 44000000;
@@ -705,7 +704,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
/* TODO DC offset removal, config parameter ? */
- if (p->u.qpsk.symbol_rate > 29000000)
+ if (p->symbol_rate > 29000000)
s5h1420_writereg(state, QPSK01, 0xae | 0x10);
else
s5h1420_writereg(state, QPSK01, 0xac | 0x10);
@@ -718,15 +717,15 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
s5h1420_writereg(state, Loop01, 0xF0);
s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */
s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */
- if (p->u.qpsk.symbol_rate > 20000000)
+ if (p->symbol_rate > 20000000)
s5h1420_writereg(state, Loop04, 0x79);
else
s5h1420_writereg(state, Loop04, 0x58);
s5h1420_writereg(state, Loop05, 0x6b);
- if (p->u.qpsk.symbol_rate >= 8000000)
+ if (p->symbol_rate >= 8000000)
s5h1420_writereg(state, Post01, (0 << 6) | 0x10);
- else if (p->u.qpsk.symbol_rate >= 4000000)
+ else if (p->symbol_rate >= 4000000)
s5h1420_writereg(state, Post01, (1 << 6) | 0x10);
else
s5h1420_writereg(state, Post01, (3 << 6) | 0x10);
@@ -744,7 +743,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
/* set tuner PLL */
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
s5h1420_setfreqoffset(state, 0);
@@ -757,8 +756,8 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
/* start QPSK */
s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1);
- state->fec_inner = p->u.qpsk.fec_inner;
- state->symbol_rate = p->u.qpsk.symbol_rate;
+ state->fec_inner = p->fec_inner;
+ state->symbol_rate = p->symbol_rate;
state->postlocked = 0;
state->tunedfreq = p->frequency;
@@ -766,15 +765,15 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
return 0;
}
-static int s5h1420_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *p)
+static int s5h1420_get_frontend(struct dvb_frontend* fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s5h1420_state* state = fe->demodulator_priv;
p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
p->inversion = s5h1420_getinversion(state);
- p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state);
- p->u.qpsk.fec_inner = s5h1420_getfec(state);
+ p->symbol_rate = s5h1420_getsymbolrate(state);
+ p->fec_inner = s5h1420_getfec(state);
return 0;
}
@@ -782,29 +781,30 @@ static int s5h1420_get_frontend(struct dvb_frontend* fe,
static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
struct dvb_frontend_tune_settings* fesettings)
{
- if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ if (p->symbol_rate > 20000000) {
fesettings->min_delay_ms = 50;
fesettings->step_size = 2000;
fesettings->max_drift = 8000;
- } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
+ } else if (p->symbol_rate > 12000000) {
fesettings->min_delay_ms = 100;
fesettings->step_size = 1500;
fesettings->max_drift = 9000;
- } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
+ } else if (p->symbol_rate > 8000000) {
fesettings->min_delay_ms = 100;
fesettings->step_size = 1000;
fesettings->max_drift = 8000;
- } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
+ } else if (p->symbol_rate > 4000000) {
fesettings->min_delay_ms = 100;
fesettings->step_size = 500;
fesettings->max_drift = 7000;
- } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
+ } else if (p->symbol_rate > 2000000) {
fesettings->min_delay_ms = 200;
- fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+ fesettings->step_size = (p->symbol_rate / 8000);
fesettings->max_drift = 14 * fesettings->step_size;
} else {
fesettings->min_delay_ms = 200;
- fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+ fesettings->step_size = (p->symbol_rate / 8000);
fesettings->max_drift = 18 * fesettings->step_size;
}
@@ -937,10 +937,9 @@ error:
EXPORT_SYMBOL(s5h1420_attach);
static struct dvb_frontend_ops s5h1420_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "Samsung S5H1420/PnpNetwork PN1010 DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 125, /* kHz for QPSK frontends */
diff --git a/drivers/media/dvb/frontends/s5h1432.c b/drivers/media/dvb/frontends/s5h1432.c
index 0c6dcb90d168..8352ce1c9556 100644
--- a/drivers/media/dvb/frontends/s5h1432.c
+++ b/drivers/media/dvb/frontends/s5h1432.c
@@ -178,9 +178,9 @@ static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz)
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1432_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int s5h1432_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 dvb_bandwidth = 8;
struct s5h1432_state *state = fe->demodulator_priv;
@@ -188,26 +188,26 @@ static int s5h1432_set_frontend(struct dvb_frontend *fe,
/*current_frequency = p->frequency; */
/*state->current_frequency = p->frequency; */
} else {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
msleep(300);
s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
- switch (p->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (p->bandwidth_hz) {
+ case 6000000:
dvb_bandwidth = 6;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
dvb_bandwidth = 7;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
dvb_bandwidth = 8;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
default:
return 0;
}
- /*fe->ops.tuner_ops.set_params(fe, p); */
+ /*fe->ops.tuner_ops.set_params(fe); */
/*Soft Reset chip*/
msleep(30);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
@@ -215,23 +215,23 @@ static int s5h1432_set_frontend(struct dvb_frontend *fe,
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
- switch (p->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (p->bandwidth_hz) {
+ case 6000000:
dvb_bandwidth = 6;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
dvb_bandwidth = 7;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
dvb_bandwidth = 8;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
default:
return 0;
}
- /*fe->ops.tuner_ops.set_params(fe,p); */
+ /*fe->ops.tuner_ops.set_params(fe); */
/*Soft Reset chip*/
msleep(30);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
@@ -329,12 +329,6 @@ static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber)
return 0;
}
-static int s5h1432_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
-{
- return 0;
-}
-
static int s5h1432_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *tune)
{
@@ -381,10 +375,9 @@ error:
EXPORT_SYMBOL(s5h1432_attach);
static struct dvb_frontend_ops s5h1432_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "Samsung s5h1432 DVB-T Frontend",
- .type = FE_OFDM,
.frequency_min = 177000000,
.frequency_max = 858000000,
.frequency_stepsize = 166666,
@@ -397,7 +390,6 @@ static struct dvb_frontend_ops s5h1432_ops = {
.init = s5h1432_init,
.sleep = s5h1432_sleep,
.set_frontend = s5h1432_set_frontend,
- .get_frontend = s5h1432_get_frontend,
.get_tune_settings = s5h1432_get_tune_settings,
.read_status = s5h1432_read_status,
.read_ber = s5h1432_read_ber,
diff --git a/drivers/media/dvb/frontends/s921.c b/drivers/media/dvb/frontends/s921.c
index ca0103d5f148..cd2288c07147 100644
--- a/drivers/media/dvb/frontends/s921.c
+++ b/drivers/media/dvb/frontends/s921.c
@@ -262,9 +262,9 @@ static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg)
s921_i2c_writeregdata(state, state->config->demod_address, \
regdata, ARRAY_SIZE(regdata))
-static int s921_pll_tune(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int s921_pll_tune(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s921_state *state = fe->demodulator_priv;
int band, rc, i;
unsigned long f_offset;
@@ -414,9 +414,9 @@ static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
return 0;
}
-static int s921_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int s921_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s921_state *state = fe->demodulator_priv;
int rc;
@@ -424,7 +424,7 @@ static int s921_set_frontend(struct dvb_frontend *fe,
/* FIXME: We don't know how to use non-auto mode */
- rc = s921_pll_tune(fe, p);
+ rc = s921_pll_tune(fe);
if (rc < 0)
return rc;
@@ -433,19 +433,20 @@ static int s921_set_frontend(struct dvb_frontend *fe,
return 0;
}
-static int s921_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int s921_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct s921_state *state = fe->demodulator_priv;
/* FIXME: Probably it is possible to get it from regs f1 and f2 */
p->frequency = state->currentfreq;
+ p->delivery_system = SYS_ISDBT;
return 0;
}
static int s921_tune(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
+ bool re_tune,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status)
@@ -454,8 +455,8 @@ static int s921_tune(struct dvb_frontend *fe,
dprintk("\n");
- if (params != NULL)
- rc = s921_set_frontend(fe, params);
+ if (re_tune)
+ rc = s921_set_frontend(fe);
if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
s921_read_status(fe, status);
@@ -510,10 +511,10 @@ rcor:
EXPORT_SYMBOL(s921_attach);
static struct dvb_frontend_ops s921_ops = {
+ .delsys = { SYS_ISDBT },
/* Use dib8000 values per default */
.info = {
.name = "Sharp S921",
- .type = FE_OFDM,
.frequency_min = 470000000,
/*
* Max should be 770MHz instead, according with Sharp docs,
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c
index 4b0c99a08a85..a68a64800df7 100644
--- a/drivers/media/dvb/frontends/si21xx.c
+++ b/drivers/media/dvb/frontends/si21xx.c
@@ -690,20 +690,7 @@ static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate,
return status;
}
-static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p)
-{
- dprintk("%s(..)\n", __func__);
- return 0;
-}
-
-static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p)
-{
- dprintk("%s(..)\n", __func__);
- return 0;
-}
-
-static int si21xx_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *dfp)
+static int si21xx_set_frontend(struct dvb_frontend *fe)
{
struct si21xx_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -877,10 +864,9 @@ static void si21xx_release(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops si21xx_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "SL SI21XX DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 125, /* kHz for QPSK frontends */
@@ -908,8 +894,6 @@ static struct dvb_frontend_ops si21xx_ops = {
.set_tone = si21xx_set_tone,
.set_voltage = si21xx_set_voltage,
- .set_property = si21xx_set_property,
- .get_property = si21xx_get_property,
.set_frontend = si21xx_set_frontend,
};
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index b85eb60a893e..e37274c8f14e 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -168,13 +168,13 @@ static int sp8870_read_data_valid_signal(struct sp8870_state* state)
return (sp8870_readreg(state, 0x0D02) > 0);
}
-static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
+static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05)
{
int known_parameters = 1;
*reg0xc05 = 0x000;
- switch (p->u.ofdm.constellation) {
+ switch (p->modulation) {
case QPSK:
break;
case QAM_16:
@@ -190,7 +190,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
return -EINVAL;
};
- switch (p->u.ofdm.hierarchy_information) {
+ switch (p->hierarchy) {
case HIERARCHY_NONE:
break;
case HIERARCHY_1:
@@ -209,7 +209,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
return -EINVAL;
};
- switch (p->u.ofdm.code_rate_HP) {
+ switch (p->code_rate_HP) {
case FEC_1_2:
break;
case FEC_2_3:
@@ -245,9 +245,9 @@ static int sp8870_wake_up(struct sp8870_state* state)
return sp8870_writereg(state, 0xC18, 0x00D);
}
-static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
- struct dvb_frontend_parameters *p)
+static int sp8870_set_frontend_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct sp8870_state* state = fe->demodulator_priv;
int err;
u16 reg0xc05;
@@ -260,7 +260,7 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
// set tuner parameters
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -277,15 +277,15 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
sp8870_writereg(state, 0x030A, 0x0000);
// filter for 6/7/8 Mhz channel
- if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+ if (p->bandwidth_hz == 6000000)
sp8870_writereg(state, 0x0311, 0x0002);
- else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+ else if (p->bandwidth_hz == 7000000)
sp8870_writereg(state, 0x0311, 0x0001);
else
sp8870_writereg(state, 0x0311, 0x0000);
// scan order: 2k first = 0x0000, 8k first = 0x0001
- if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
+ if (p->transmission_mode == TRANSMISSION_MODE_2K)
sp8870_writereg(state, 0x0338, 0x0000);
else
sp8870_writereg(state, 0x0338, 0x0001);
@@ -459,8 +459,9 @@ static int lockups;
/* only for debugging: counter for channel switches */
static int switches;
-static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int sp8870_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct sp8870_state* state = fe->demodulator_priv;
/*
@@ -479,7 +480,8 @@ static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_par
for (trials = 1; trials <= MAXTRIALS; trials++) {
- if ((err = sp8870_set_frontend_parameters(fe, p)))
+ err = sp8870_set_frontend_parameters(fe);
+ if (err)
return err;
for (check_count = 0; check_count < MAXCHECKS; check_count++) {
@@ -579,10 +581,9 @@ error:
}
static struct dvb_frontend_ops sp8870_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "Spase SP8870 DVB-T",
- .type = FE_OFDM,
.frequency_min = 470000000,
.frequency_max = 860000000,
.frequency_stepsize = 166666,
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index 4a7c3d842608..f4096ccb226e 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -209,13 +209,13 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware
return 0;
};
-static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
+static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05)
{
int known_parameters = 1;
*reg0xc05 = 0x000;
- switch (p->u.ofdm.constellation) {
+ switch (p->modulation) {
case QPSK:
break;
case QAM_16:
@@ -231,7 +231,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
return -EINVAL;
};
- switch (p->u.ofdm.hierarchy_information) {
+ switch (p->hierarchy) {
case HIERARCHY_NONE:
break;
case HIERARCHY_1:
@@ -250,7 +250,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
return -EINVAL;
};
- switch (p->u.ofdm.code_rate_HP) {
+ switch (p->code_rate_HP) {
case FEC_1_2:
break;
case FEC_2_3:
@@ -303,17 +303,30 @@ static void divide (int n, int d, int *quotient_i, int *quotient_f)
}
static void sp887x_correct_offsets (struct sp887x_state* state,
- struct dvb_frontend_parameters *p,
+ struct dtv_frontend_properties *p,
int actual_freq)
{
static const u32 srate_correction [] = { 1879617, 4544878, 8098561 };
- int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
+ int bw_index;
int freq_offset = actual_freq - p->frequency;
int sysclock = 61003; //[kHz]
int ifreq = 36000000;
int freq;
int frequency_shift;
+ switch (p->bandwidth_hz) {
+ default:
+ case 8000000:
+ bw_index = 0;
+ break;
+ case 7000000:
+ bw_index = 1;
+ break;
+ case 6000000:
+ bw_index = 2;
+ break;
+ }
+
if (p->inversion == INVERSION_ON)
freq = ifreq - freq_offset;
else
@@ -333,17 +346,17 @@ static void sp887x_correct_offsets (struct sp887x_state* state,
sp887x_writereg(state, 0x30a, frequency_shift & 0xfff);
}
-static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
- struct dvb_frontend_parameters *p)
+static int sp887x_setup_frontend_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct sp887x_state* state = fe->demodulator_priv;
unsigned actual_freq;
int err;
u16 val, reg0xc05;
- if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ &&
- p->u.ofdm.bandwidth != BANDWIDTH_7_MHZ &&
- p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ)
+ if (p->bandwidth_hz != 8000000 &&
+ p->bandwidth_hz != 7000000 &&
+ p->bandwidth_hz != 6000000)
return -EINVAL;
if ((err = configure_reg0xc05(p, &reg0xc05)))
@@ -353,7 +366,7 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
/* setup the PLL */
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
if (fe->ops.tuner_ops.get_frequency) {
@@ -369,9 +382,9 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
sp887x_correct_offsets(state, p, actual_freq);
/* filter for 6/7/8 Mhz channel */
- if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+ if (p->bandwidth_hz == 6000000)
val = 2;
- else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+ else if (p->bandwidth_hz == 7000000)
val = 1;
else
val = 0;
@@ -379,16 +392,16 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
sp887x_writereg(state, 0x311, val);
/* scan order: 2k first = 0, 8k first = 1 */
- if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
+ if (p->transmission_mode == TRANSMISSION_MODE_2K)
sp887x_writereg(state, 0x338, 0x000);
else
sp887x_writereg(state, 0x338, 0x001);
sp887x_writereg(state, 0xc05, reg0xc05);
- if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+ if (p->bandwidth_hz == 6000000)
val = 2 << 3;
- else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+ else if (p->bandwidth_hz == 7000000)
val = 3 << 3;
else
val = 0 << 3;
@@ -579,10 +592,9 @@ error:
}
static struct dvb_frontend_ops sp887x_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "Spase SP887x DVB-T",
- .type = FE_OFDM,
.frequency_min = 50500000,
.frequency_max = 858000000,
.frequency_stepsize = 166666,
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
index 8408ef877b4b..dd08f4ac64a8 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/drivers/media/dvb/frontends/stb0899_drv.c
@@ -67,7 +67,7 @@ static const struct stb0899_tab stb0899_cn_tab[] = {
* Crude linear extrapolation below -84.8dBm and above -8.0dBm.
*/
static const struct stb0899_tab stb0899_dvbsrf_tab[] = {
- { -950, -128 },
+ { -750, -128 },
{ -748, -94 },
{ -745, -92 },
{ -735, -90 },
@@ -131,7 +131,7 @@ static const struct stb0899_tab stb0899_dvbs2rf_tab[] = {
{ -730, 13645 },
{ -750, 13909 },
{ -766, 14153 },
- { -999, 16383 }
+ { -950, 16383 }
};
/* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/
@@ -964,6 +964,7 @@ static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
int val;
u32 reg;
+ *strength = 0;
switch (state->delsys) {
case SYS_DVBS:
case SYS_DSS:
@@ -983,11 +984,11 @@ static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
break;
case SYS_DVBS2:
if (internal->lock) {
- reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN);
+ reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_GAIN);
val = STB0899_GETFIELD(IF_AGC_GAIN, reg);
*strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val);
- *strength += 750;
+ *strength += 950;
dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm",
val & 0x3fff, *strength);
}
@@ -1009,6 +1010,7 @@ static int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr)
u8 buf[2];
u32 reg;
+ *snr = 0;
reg = stb0899_read_reg(state, STB0899_VSTATUS);
switch (state->delsys) {
case SYS_DVBS:
@@ -1071,7 +1073,7 @@ static int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status)
reg = stb0899_read_reg(state, STB0899_VSTATUS);
if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK");
- *status |= FE_HAS_CARRIER | FE_HAS_LOCK;
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
reg = stb0899_read_reg(state, STB0899_PLPARM);
if (STB0899_GETFIELD(VITCURPUN, reg)) {
@@ -1431,7 +1433,7 @@ static void stb0899_set_iterations(struct stb0899_state *state)
stb0899_write_s2reg(state, STB0899_S2FEC, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg);
}
-static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static enum dvbfe_search stb0899_search(struct dvb_frontend *fe)
{
struct stb0899_state *state = fe->demodulator_priv;
struct stb0899_params *i_params = &state->params;
@@ -1441,8 +1443,8 @@ static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_fron
u32 SearchRange, gain;
- i_params->freq = p->frequency;
- i_params->srate = p->u.qpsk.symbol_rate;
+ i_params->freq = props->frequency;
+ i_params->srate = props->symbol_rate;
state->delsys = props->delivery_system;
dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys);
@@ -1568,34 +1570,15 @@ static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_fron
return DVBFE_ALGO_SEARCH_ERROR;
}
-/*
- * stb0899_track
- * periodically check the signal level against a specified
- * threshold level and perform derotator centering.
- * called once we have a lock from a successful search
- * event.
- *
- * Will be called periodically called to maintain the
- * lock.
- *
- * Will be used to get parameters as well as info from
- * the decoded baseband header
- *
- * Once a new lock has established, the internal state
- * frequency (internal->freq) is updated
- */
-static int stb0899_track(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
-{
- return 0;
-}
-static int stb0899_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int stb0899_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stb0899_state *state = fe->demodulator_priv;
struct stb0899_internal *internal = &state->internal;
dprintk(state->verbose, FE_DEBUG, 1, "Get params");
- p->u.qpsk.symbol_rate = internal->srate;
+ p->symbol_rate = internal->srate;
return 0;
}
@@ -1606,10 +1589,9 @@ static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops stb0899_ops = {
-
+ .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
.info = {
.name = "STB0899 Multistandard",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 0,
@@ -1632,8 +1614,7 @@ static struct dvb_frontend_ops stb0899_ops = {
.get_frontend_algo = stb0899_frontend_algo,
.search = stb0899_search,
- .track = stb0899_track,
- .get_frontend = stb0899_get_frontend,
+ .get_frontend = stb0899_get_frontend,
.read_status = stb0899_read_status,
diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb/frontends/stb6000.c
index ed699647050e..a0c3c526b132 100644
--- a/drivers/media/dvb/frontends/stb6000.c
+++ b/drivers/media/dvb/frontends/stb6000.c
@@ -75,9 +75,9 @@ static int stb6000_sleep(struct dvb_frontend *fe)
return (ret == 1) ? 0 : ret;
}
-static int stb6000_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int stb6000_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stb6000_priv *priv = fe->tuner_priv;
unsigned int n, m;
int ret;
@@ -93,8 +93,8 @@ static int stb6000_set_params(struct dvb_frontend *fe,
dprintk("%s:\n", __func__);
- freq_mhz = params->frequency / 1000;
- bandwidth = params->u.qpsk.symbol_rate / 1000000;
+ freq_mhz = p->frequency / 1000;
+ bandwidth = p->symbol_rate / 1000000;
if (bandwidth > 31)
bandwidth = 31;
diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c
index bc1a8af4f6e1..def88abb30bf 100644
--- a/drivers/media/dvb/frontends/stb6100.c
+++ b/drivers/media/dvb/frontends/stb6100.c
@@ -327,7 +327,7 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
int rc;
const struct stb6100_lkup *ptr;
struct stb6100_state *state = fe->tuner_priv;
- struct dvb_frontend_parameters p;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 srate = 0, fvco, nint, nfrac;
u8 regs[STB6100_NUMREGS];
@@ -337,9 +337,9 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
if (fe->ops.get_frontend) {
dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
- fe->ops.get_frontend(fe, &p);
+ fe->ops.get_frontend(fe);
}
- srate = p.u.qpsk.symbol_rate;
+ srate = p->symbol_rate;
/* Set up tuner cleanly, LPF calibration on */
rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK);
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c
index 0aa3962ff18b..632b25156e4c 100644
--- a/drivers/media/dvb/frontends/stv0288.c
+++ b/drivers/media/dvb/frontends/stv0288.c
@@ -452,14 +452,7 @@ static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p)
return 0;
}
-static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p)
-{
- dprintk("%s(..)\n", __func__);
- return 0;
-}
-
-static int stv0288_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *dfp)
+static int stv0288_set_frontend(struct dvb_frontend *fe)
{
struct stv0288_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -481,10 +474,8 @@ static int stv0288_set_frontend(struct dvb_frontend *fe,
state->config->set_ts_params(fe, 0);
/* only frequency & symbol_rate are used for tuner*/
- dfp->frequency = c->frequency;
- dfp->u.qpsk.symbol_rate = c->symbol_rate;
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, dfp);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -515,7 +506,7 @@ static int stv0288_set_frontend(struct dvb_frontend *fe,
tda[1] = (unsigned char)tm;
stv0288_writeregI(state, 0x2b, tda[1]);
stv0288_writeregI(state, 0x2c, tda[2]);
- udelay(30);
+ msleep(30);
}
state->tuner_frequency = c->frequency;
state->fec_inner = FEC_AUTO;
@@ -545,10 +536,9 @@ static void stv0288_release(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops stv0288_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "ST STV0288 DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1000, /* kHz for QPSK frontends */
@@ -578,7 +568,6 @@ static struct dvb_frontend_ops stv0288_ops = {
.set_voltage = stv0288_set_voltage,
.set_property = stv0288_set_property,
- .get_property = stv0288_get_property,
.set_frontend = stv0288_set_frontend,
};
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index 84d88f33275e..85c157a1fe5e 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -404,8 +404,9 @@ static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
return 0;
}
-static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int stv0297_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0297_state *state = fe->demodulator_priv;
int u_threshold;
int initial_u;
@@ -417,7 +418,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
unsigned long timeout;
fe_spectral_inversion_t inversion;
- switch (p->u.qam.modulation) {
+ switch (p->modulation) {
case QAM_16:
case QAM_32:
case QAM_64:
@@ -455,7 +456,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
stv0297_init(fe);
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -519,16 +520,16 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
stv0297_writereg_mask(state, 0x69, 0x0f, 0x00);
/* set parameters */
- stv0297_set_qam(state, p->u.qam.modulation);
- stv0297_set_symbolrate(state, p->u.qam.symbol_rate / 1000);
- stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000);
+ stv0297_set_qam(state, p->modulation);
+ stv0297_set_symbolrate(state, p->symbol_rate / 1000);
+ stv0297_set_sweeprate(state, sweeprate, p->symbol_rate / 1000);
stv0297_set_carrieroffset(state, carrieroffset);
stv0297_set_inversion(state, inversion);
/* kick off lock */
/* Disable corner detection for higher QAMs */
- if (p->u.qam.modulation == QAM_128 ||
- p->u.qam.modulation == QAM_256)
+ if (p->modulation == QAM_128 ||
+ p->modulation == QAM_256)
stv0297_writereg_mask(state, 0x88, 0x08, 0x00);
else
stv0297_writereg_mask(state, 0x88, 0x08, 0x08);
@@ -613,8 +614,9 @@ timeout:
return 0;
}
-static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int stv0297_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0297_state *state = fe->demodulator_priv;
int reg_00, reg_83;
@@ -625,24 +627,24 @@ static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF;
if (state->config->invert)
p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON;
- p->u.qam.symbol_rate = stv0297_get_symbolrate(state) * 1000;
- p->u.qam.fec_inner = FEC_NONE;
+ p->symbol_rate = stv0297_get_symbolrate(state) * 1000;
+ p->fec_inner = FEC_NONE;
switch ((reg_00 >> 4) & 0x7) {
case 0:
- p->u.qam.modulation = QAM_16;
+ p->modulation = QAM_16;
break;
case 1:
- p->u.qam.modulation = QAM_32;
+ p->modulation = QAM_32;
break;
case 2:
- p->u.qam.modulation = QAM_128;
+ p->modulation = QAM_128;
break;
case 3:
- p->u.qam.modulation = QAM_256;
+ p->modulation = QAM_256;
break;
case 4:
- p->u.qam.modulation = QAM_64;
+ p->modulation = QAM_64;
break;
}
@@ -688,10 +690,9 @@ error:
}
static struct dvb_frontend_ops stv0297_ops = {
-
+ .delsys = { SYS_DVBC_ANNEX_A },
.info = {
.name = "ST STV0297 DVB-C",
- .type = FE_QAM,
.frequency_min = 47000000,
.frequency_max = 862000000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 42684bec8883..057b5f8effc0 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -559,8 +559,9 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
+static int stv0299_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0299_state* state = fe->demodulator_priv;
int invval = 0;
@@ -579,24 +580,25 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- stv0299_set_FEC (state, p->u.qpsk.fec_inner);
- stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
+ stv0299_set_FEC(state, p->fec_inner);
+ stv0299_set_symbolrate(fe, p->symbol_rate);
stv0299_writeregI(state, 0x22, 0x00);
stv0299_writeregI(state, 0x23, 0x00);
state->tuner_frequency = p->frequency;
- state->fec_inner = p->u.qpsk.fec_inner;
- state->symbol_rate = p->u.qpsk.symbol_rate;
+ state->fec_inner = p->fec_inner;
+ state->symbol_rate = p->symbol_rate;
return 0;
}
-static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
+static int stv0299_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0299_state* state = fe->demodulator_priv;
s32 derot_freq;
int invval;
@@ -614,8 +616,8 @@ static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
if (state->config->invert) invval = (~invval) & 1;
p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
- p->u.qpsk.fec_inner = stv0299_get_fec (state);
- p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state);
+ p->fec_inner = stv0299_get_fec(state);
+ p->symbol_rate = stv0299_get_symbolrate(state);
return 0;
}
@@ -646,14 +648,15 @@ static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
struct stv0299_state* state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
fesettings->min_delay_ms = state->config->min_delay_ms;
- if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) {
- fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000;
+ if (p->symbol_rate < 10000000) {
+ fesettings->step_size = p->symbol_rate / 32000;
fesettings->max_drift = 5000;
} else {
- fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000;
- fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000;
+ fesettings->step_size = p->symbol_rate / 16000;
+ fesettings->max_drift = p->symbol_rate / 2000;
}
return 0;
}
@@ -705,10 +708,9 @@ error:
}
static struct dvb_frontend_ops stv0299_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "ST STV0299 DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 125, /* kHz for QPSK frontends */
diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c
index e57ab53e2e27..fdd20c7737b5 100644
--- a/drivers/media/dvb/frontends/stv0367.c
+++ b/drivers/media/dvb/frontends/stv0367.c
@@ -1577,9 +1577,9 @@ int stv0367ter_init(struct dvb_frontend *fe)
return 0;
}
-static int stv0367ter_algo(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int stv0367ter_algo(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0367_state *state = fe->demodulator_priv;
struct stv0367ter_state *ter_state = state->ter_state;
int offset = 0, tempo = 0;
@@ -1591,7 +1591,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe,
dprintk("%s:\n", __func__);
- ter_state->frequency = param->frequency;
+ ter_state->frequency = p->frequency;
ter_state->force = FE_TER_FORCENONE
+ stv0367_readbits(state, F367TER_FORCE) * 2;
ter_state->if_iq_mode = state->config->if_iq_mode;
@@ -1620,7 +1620,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe,
usleep_range(5000, 7000);
- switch (param->inversion) {
+ switch (p->inversion) {
case INVERSION_AUTO:
default:
dprintk("%s: inversion AUTO\n", __func__);
@@ -1636,10 +1636,10 @@ static int stv0367ter_algo(struct dvb_frontend *fe,
case INVERSION_OFF:
if (ter_state->if_iq_mode == FE_TER_IQ_TUNER)
stv0367_writebits(state, F367TER_IQ_INVERT,
- param->inversion);
+ p->inversion);
else
stv0367_writebits(state, F367TER_INV_SPECTR,
- param->inversion);
+ p->inversion);
break;
}
@@ -1806,10 +1806,9 @@ static int stv0367ter_algo(struct dvb_frontend *fe,
return 0;
}
-static int stv0367ter_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int stv0367ter_set_frontend(struct dvb_frontend *fe)
{
- struct dvb_ofdm_parameters *op = &param->u.ofdm;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0367_state *state = fe->demodulator_priv;
struct stv0367ter_state *ter_state = state->ter_state;
@@ -1822,12 +1821,12 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe,
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- fe->ops.tuner_ops.set_params(fe, param);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
- switch (op->transmission_mode) {
+ switch (p->transmission_mode) {
default:
case TRANSMISSION_MODE_AUTO:
case TRANSMISSION_MODE_2K:
@@ -1841,34 +1840,34 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe,
break;
}
- switch (op->guard_interval) {
+ switch (p->guard_interval) {
default:
case GUARD_INTERVAL_1_32:
case GUARD_INTERVAL_1_16:
case GUARD_INTERVAL_1_8:
case GUARD_INTERVAL_1_4:
- ter_state->guard = op->guard_interval;
+ ter_state->guard = p->guard_interval;
break;
case GUARD_INTERVAL_AUTO:
ter_state->guard = GUARD_INTERVAL_1_32;
break;
}
- switch (op->bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (p->bandwidth_hz) {
+ case 6000000:
ter_state->bw = FE_TER_CHAN_BW_6M;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
ter_state->bw = FE_TER_CHAN_BW_7M;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
default:
ter_state->bw = FE_TER_CHAN_BW_8M;
}
ter_state->hierarchy = FE_TER_HIER_NONE;
- switch (param->inversion) {
+ switch (p->inversion) {
case INVERSION_OFF:
case INVERSION_ON:
num_trials = 1;
@@ -1885,14 +1884,14 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe,
while (((index) < num_trials) && (ter_state->state != FE_TER_LOCKOK)) {
if (!ter_state->first_lock) {
- if (param->inversion == INVERSION_AUTO)
+ if (p->inversion == INVERSION_AUTO)
ter_state->sense = SenseTrials[index];
}
- stv0367ter_algo(fe,/* &pLook, result,*/ param);
+ stv0367ter_algo(fe);
if ((ter_state->state == FE_TER_LOCKOK) &&
- (param->inversion == INVERSION_AUTO) &&
+ (p->inversion == INVERSION_AUTO) &&
(index == 1)) {
/* invert spectrum sense */
SenseTrials[index] = SenseTrials[0];
@@ -1927,50 +1926,48 @@ static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
return 0;
}
-static int stv0367ter_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int stv0367ter_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0367_state *state = fe->demodulator_priv;
struct stv0367ter_state *ter_state = state->ter_state;
- struct dvb_ofdm_parameters *op = &param->u.ofdm;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int error = 0;
enum stv0367_ter_mode mode;
int constell = 0,/* snr = 0,*/ Data = 0;
- param->frequency = stv0367_get_tuner_freq(fe);
- if ((int)param->frequency < 0)
- param->frequency = c->frequency;
+ p->frequency = stv0367_get_tuner_freq(fe);
+ if ((int)p->frequency < 0)
+ p->frequency = -p->frequency;
constell = stv0367_readbits(state, F367TER_TPS_CONST);
if (constell == 0)
- op->constellation = QPSK;
+ p->modulation = QPSK;
else if (constell == 1)
- op->constellation = QAM_16;
+ p->modulation = QAM_16;
else
- op->constellation = QAM_64;
+ p->modulation = QAM_64;
- param->inversion = stv0367_readbits(state, F367TER_INV_SPECTR);
+ p->inversion = stv0367_readbits(state, F367TER_INV_SPECTR);
/* Get the Hierarchical mode */
Data = stv0367_readbits(state, F367TER_TPS_HIERMODE);
switch (Data) {
case 0:
- op->hierarchy_information = HIERARCHY_NONE;
+ p->hierarchy = HIERARCHY_NONE;
break;
case 1:
- op->hierarchy_information = HIERARCHY_1;
+ p->hierarchy = HIERARCHY_1;
break;
case 2:
- op->hierarchy_information = HIERARCHY_2;
+ p->hierarchy = HIERARCHY_2;
break;
case 3:
- op->hierarchy_information = HIERARCHY_4;
+ p->hierarchy = HIERARCHY_4;
break;
default:
- op->hierarchy_information = HIERARCHY_AUTO;
+ p->hierarchy = HIERARCHY_AUTO;
break; /* error */
}
@@ -1982,22 +1979,22 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe,
switch (Data) {
case 0:
- op->code_rate_HP = FEC_1_2;
+ p->code_rate_HP = FEC_1_2;
break;
case 1:
- op->code_rate_HP = FEC_2_3;
+ p->code_rate_HP = FEC_2_3;
break;
case 2:
- op->code_rate_HP = FEC_3_4;
+ p->code_rate_HP = FEC_3_4;
break;
case 3:
- op->code_rate_HP = FEC_5_6;
+ p->code_rate_HP = FEC_5_6;
break;
case 4:
- op->code_rate_HP = FEC_7_8;
+ p->code_rate_HP = FEC_7_8;
break;
default:
- op->code_rate_HP = FEC_AUTO;
+ p->code_rate_HP = FEC_AUTO;
break; /* error */
}
@@ -2005,19 +2002,19 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe,
switch (mode) {
case FE_TER_MODE_2K:
- op->transmission_mode = TRANSMISSION_MODE_2K;
+ p->transmission_mode = TRANSMISSION_MODE_2K;
break;
/* case FE_TER_MODE_4K:
- op->transmission_mode = TRANSMISSION_MODE_4K;
+ p->transmission_mode = TRANSMISSION_MODE_4K;
break;*/
case FE_TER_MODE_8K:
- op->transmission_mode = TRANSMISSION_MODE_8K;
+ p->transmission_mode = TRANSMISSION_MODE_8K;
break;
default:
- op->transmission_mode = TRANSMISSION_MODE_AUTO;
+ p->transmission_mode = TRANSMISSION_MODE_AUTO;
}
- op->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD);
+ p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD);
return error;
}
@@ -2265,9 +2262,9 @@ static void stv0367_release(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops stv0367ter_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "ST STV0367 DVB-T",
- .type = FE_OFDM,
.frequency_min = 47000000,
.frequency_max = 862000000,
.frequency_stepsize = 15625,
@@ -2822,9 +2819,8 @@ int stv0367cab_init(struct dvb_frontend *fe)
}
static
enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
- struct dvb_frontend_parameters *param)
+ struct dtv_frontend_properties *p)
{
- struct dvb_qam_parameters *op = &param->u.qam;
struct stv0367cab_state *cab_state = state->cab_state;
enum stv0367_cab_signal_type signalType = FE_CAB_NOAGC;
u32 QAMFEC_Lock, QAM_Lock, u32_tmp,
@@ -2839,7 +2835,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
/* A max lock time of 25 ms is allowed for delayed AGC */
AGCTimeOut = 25;
/* 100000 symbols needed by the TRL as a maximum value */
- TRLTimeOut = 100000000 / op->symbol_rate;
+ TRLTimeOut = 100000000 / p->symbol_rate;
/* CRLSymbols is the needed number of symbols to achieve a lock
within [-4%, +4%] of the symbol rate.
CRL timeout is calculated
@@ -2849,7 +2845,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
A characterization must be performed
with these echoes to get new timeout values.
*/
- switch (op->modulation) {
+ switch (p->modulation) {
case QAM_16:
CRLSymbols = 150000;
EQLTimeOut = 100;
@@ -2883,9 +2879,9 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
} else
#endif
CRLTimeOut = (25 * CRLSymbols * (cab_state->search_range / 1000)) /
- (op->symbol_rate / 1000);
+ (p->symbol_rate / 1000);
- CRLTimeOut = (1000 * CRLTimeOut) / op->symbol_rate;
+ CRLTimeOut = (1000 * CRLTimeOut) / p->symbol_rate;
/* Timeouts below 50ms are coerced */
if (CRLTimeOut < 50)
CRLTimeOut = 50;
@@ -2915,7 +2911,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
stv0367cab_set_derot_freq(state, cab_state->adc_clk,
(1000 * (s32)state->config->if_khz + cab_state->derot_offset));
/* Disable the Allpass Filter when the symbol rate is out of range */
- if ((op->symbol_rate > 10800000) | (op->symbol_rate < 1800000)) {
+ if ((p->symbol_rate > 10800000) | (p->symbol_rate < 1800000)) {
stv0367_writebits(state, F367CAB_ADJ_EN, 0);
stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0);
}
@@ -2999,7 +2995,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
if (QAMFEC_Lock) {
signalType = FE_CAB_DATAOK;
- cab_state->modulation = op->modulation;
+ cab_state->modulation = p->modulation;
cab_state->spect_inv = stv0367_readbits(state,
F367CAB_QUAD_INV);
#if 0
@@ -3081,20 +3077,19 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
return signalType;
}
-static int stv0367cab_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int stv0367cab_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0367_state *state = fe->demodulator_priv;
struct stv0367cab_state *cab_state = state->cab_state;
- struct dvb_qam_parameters *op = &param->u.qam;
enum stv0367cab_mod QAMSize = 0;
dprintk("%s: freq = %d, srate = %d\n", __func__,
- param->frequency, op->symbol_rate);
+ p->frequency, p->symbol_rate);
cab_state->derot_offset = 0;
- switch (op->modulation) {
+ switch (p->modulation) {
case QAM_16:
QAMSize = FE_CAB_MOD_QAM16;
break;
@@ -3120,77 +3115,76 @@ static int stv0367cab_set_frontend(struct dvb_frontend *fe,
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- fe->ops.tuner_ops.set_params(fe, param);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
stv0367cab_SetQamSize(
state,
- op->symbol_rate,
+ p->symbol_rate,
QAMSize);
stv0367cab_set_srate(state,
cab_state->adc_clk,
cab_state->mclk,
- op->symbol_rate,
+ p->symbol_rate,
QAMSize);
/* Search algorithm launch, [-1.1*RangeOffset, +1.1*RangeOffset] scan */
- cab_state->state = stv0367cab_algo(state, param);
+ cab_state->state = stv0367cab_algo(state, p);
return 0;
}
-static int stv0367cab_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int stv0367cab_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0367_state *state = fe->demodulator_priv;
struct stv0367cab_state *cab_state = state->cab_state;
- struct dvb_qam_parameters *op = &param->u.qam;
enum stv0367cab_mod QAMSize;
dprintk("%s:\n", __func__);
- op->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk);
+ p->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk);
QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE);
switch (QAMSize) {
case FE_CAB_MOD_QAM16:
- op->modulation = QAM_16;
+ p->modulation = QAM_16;
break;
case FE_CAB_MOD_QAM32:
- op->modulation = QAM_32;
+ p->modulation = QAM_32;
break;
case FE_CAB_MOD_QAM64:
- op->modulation = QAM_64;
+ p->modulation = QAM_64;
break;
case FE_CAB_MOD_QAM128:
- op->modulation = QAM_128;
+ p->modulation = QAM_128;
break;
case QAM_256:
- op->modulation = QAM_256;
+ p->modulation = QAM_256;
break;
default:
break;
}
- param->frequency = stv0367_get_tuner_freq(fe);
+ p->frequency = stv0367_get_tuner_freq(fe);
- dprintk("%s: tuner frequency = %d\n", __func__, param->frequency);
+ dprintk("%s: tuner frequency = %d\n", __func__, p->frequency);
if (state->config->if_khz == 0) {
- param->frequency +=
+ p->frequency +=
(stv0367cab_get_derot_freq(state, cab_state->adc_clk) -
cab_state->adc_clk / 4000);
return 0;
}
if (state->config->if_khz > cab_state->adc_clk / 1000)
- param->frequency += (state->config->if_khz
+ p->frequency += (state->config->if_khz
- stv0367cab_get_derot_freq(state, cab_state->adc_clk)
- cab_state->adc_clk / 1000);
else
- param->frequency += (state->config->if_khz
+ p->frequency += (state->config->if_khz
- stv0367cab_get_derot_freq(state, cab_state->adc_clk));
return 0;
@@ -3386,9 +3380,9 @@ static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks)
};
static struct dvb_frontend_ops stv0367cab_ops = {
+ .delsys = { SYS_DVBC_ANNEX_A },
.info = {
.name = "ST STV0367 DVB-C",
- .type = FE_QAM,
.frequency_min = 47000000,
.frequency_max = 862000000,
.frequency_stepsize = 62500,
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c
index 0ca316d6fffa..7f1badaf0d03 100644
--- a/drivers/media/dvb/frontends/stv0900_core.c
+++ b/drivers/media/dvb/frontends/stv0900_core.c
@@ -973,22 +973,6 @@ static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe)
return DVBFE_ALGO_CUSTOM;
}
-static int stb0900_set_property(struct dvb_frontend *fe,
- struct dtv_property *tvp)
-{
- dprintk("%s(..)\n", __func__);
-
- return 0;
-}
-
-static int stb0900_get_property(struct dvb_frontend *fe,
- struct dtv_property *tvp)
-{
- dprintk("%s(..)\n", __func__);
-
- return 0;
-}
-
void stv0900_start_search(struct stv0900_internal *intp,
enum fe_stv0900_demod_num demod)
{
@@ -1574,8 +1558,7 @@ static int stv0900_status(struct stv0900_internal *intp,
return locked;
}
-static enum dvbfe_search stv0900_search(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static enum dvbfe_search stv0900_search(struct dvb_frontend *fe)
{
struct stv0900_state *state = fe->demodulator_priv;
struct stv0900_internal *intp = state->internal;
@@ -1675,12 +1658,6 @@ static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status)
return 0;
}
-static int stv0900_track(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
-{
- return 0;
-}
-
static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts)
{
@@ -1866,24 +1843,23 @@ static int stv0900_sleep(struct dvb_frontend *fe)
return 0;
}
-static int stv0900_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int stv0900_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct stv0900_state *state = fe->demodulator_priv;
struct stv0900_internal *intp = state->internal;
enum fe_stv0900_demod_num demod = state->demod;
struct stv0900_signal_info p_result = intp->result[demod];
p->frequency = p_result.locked ? p_result.frequency : 0;
- p->u.qpsk.symbol_rate = p_result.locked ? p_result.symbol_rate : 0;
+ p->symbol_rate = p_result.locked ? p_result.symbol_rate : 0;
return 0;
}
static struct dvb_frontend_ops stv0900_ops = {
-
+ .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
.info = {
.name = "STV0900 frontend",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 125,
@@ -1907,10 +1883,7 @@ static struct dvb_frontend_ops stv0900_ops = {
.diseqc_send_burst = stv0900_send_burst,
.diseqc_recv_slave_reply = stv0900_recv_slave_reply,
.set_tone = stv0900_set_tone,
- .set_property = stb0900_set_property,
- .get_property = stb0900_get_property,
.search = stv0900_search,
- .track = stv0900_track,
.read_status = stv0900_read_status,
.read_ber = stv0900_read_ber,
.read_signal_strength = stv0900_read_signal_strength,
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index ebda41936b90..4aef1877ed42 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -3427,17 +3427,17 @@ err:
return -1;
}
-static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static enum dvbfe_search stv090x_search(struct dvb_frontend *fe)
{
struct stv090x_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *props = &fe->dtv_property_cache;
- if (p->frequency == 0)
+ if (props->frequency == 0)
return DVBFE_ALGO_SEARCH_INVALID;
state->delsys = props->delivery_system;
- state->frequency = p->frequency;
- state->srate = p->u.qpsk.symbol_rate;
+ state->frequency = props->frequency;
+ state->srate = props->symbol_rate;
state->search_mode = STV090x_SEARCH_AUTO;
state->algo = STV090x_COLD_SEARCH;
state->fec = STV090x_PRERR;
@@ -4712,10 +4712,9 @@ int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value,
EXPORT_SYMBOL(stv090x_set_gpio);
static struct dvb_frontend_ops stv090x_ops = {
-
+ .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
.info = {
.name = "STV090x Multistandard",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 0,
@@ -4743,7 +4742,7 @@ static struct dvb_frontend_ops stv090x_ops = {
.read_status = stv090x_read_status,
.read_ber = stv090x_read_per,
.read_signal_strength = stv090x_read_signal_strength,
- .read_snr = stv090x_read_cnr
+ .read_snr = stv090x_read_cnr,
};
diff --git a/drivers/media/dvb/frontends/stv6110.c b/drivers/media/dvb/frontends/stv6110.c
index 2dca7c8e5148..20b5fa92c53e 100644
--- a/drivers/media/dvb/frontends/stv6110.c
+++ b/drivers/media/dvb/frontends/stv6110.c
@@ -347,8 +347,7 @@ static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
return 0;
}
-static int stv6110_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int stv6110_set_params(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u32 bandwidth = carrier_width(c->symbol_rate, c->rolloff);
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 6ca533ea0f0e..1bff7f457e19 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -224,47 +224,86 @@ static int tda10021_init (struct dvb_frontend *fe)
return 0;
}
-static int tda10021_set_parameters (struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+struct qam_params {
+ u8 conf, agcref, lthr, mseth, aref;
+};
+
+static int tda10021_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
+ unsigned qam = c->modulation;
+ bool is_annex_c;
+ u32 reg0x3d;
struct tda10021_state* state = fe->demodulator_priv;
+ static const struct qam_params qam_params[] = {
+ /* Modulation Conf AGCref LTHR MSETH AREF */
+ [QPSK] = { 0x14, 0x78, 0x78, 0x8c, 0x96 },
+ [QAM_16] = { 0x00, 0x8c, 0x87, 0xa2, 0x91 },
+ [QAM_32] = { 0x04, 0x8c, 0x64, 0x74, 0x96 },
+ [QAM_64] = { 0x08, 0x6a, 0x46, 0x43, 0x6a },
+ [QAM_128] = { 0x0c, 0x78, 0x36, 0x34, 0x7e },
+ [QAM_256] = { 0x10, 0x5c, 0x26, 0x23, 0x6b },
+ };
+
+ switch (delsys) {
+ case SYS_DVBC_ANNEX_A:
+ is_annex_c = false;
+ break;
+ case SYS_DVBC_ANNEX_C:
+ is_annex_c = true;
+ break;
+ default:
+ return -EINVAL;
+ }
- //table for QAM4-QAM256 ready QAM4 QAM16 QAM32 QAM64 QAM128 QAM256
- //CONF
- static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c, 0x10 };
- //AGCREF value
- static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78, 0x5c };
- //LTHR value
- static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36, 0x26 };
- //MSETH
- static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34, 0x23 };
- //AREF
- static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e, 0x6b };
-
- int qam = p->u.qam.modulation;
-
- if (qam < 0 || qam > 5)
+ /*
+ * gcc optimizes the code bellow the same way as it would code:
+ * "if (qam > 5) return -EINVAL;"
+ * Yet, the code is clearer, as it shows what QAM standards are
+ * supported by the driver, and avoids the usage of magic numbers on
+ * it.
+ */
+ switch (qam) {
+ case QPSK:
+ case QAM_16:
+ case QAM_32:
+ case QAM_64:
+ case QAM_128:
+ case QAM_256:
+ break;
+ default:
return -EINVAL;
+ }
- if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF)
+ if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF)
return -EINVAL;
- //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
+ /*printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->symbol_rate);*/
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
- _tda10021_writereg (state, 0x34, state->pwm);
-
- _tda10021_writereg (state, 0x01, reg0x01[qam]);
- _tda10021_writereg (state, 0x05, reg0x05[qam]);
- _tda10021_writereg (state, 0x08, reg0x08[qam]);
- _tda10021_writereg (state, 0x09, reg0x09[qam]);
-
- tda10021_setup_reg0 (state, reg0x00[qam], p->inversion);
+ tda10021_set_symbolrate(state, c->symbol_rate);
+ _tda10021_writereg(state, 0x34, state->pwm);
+
+ _tda10021_writereg(state, 0x01, qam_params[qam].agcref);
+ _tda10021_writereg(state, 0x05, qam_params[qam].lthr);
+ _tda10021_writereg(state, 0x08, qam_params[qam].mseth);
+ _tda10021_writereg(state, 0x09, qam_params[qam].aref);
+
+ /*
+ * Bit 0 == 0 means roll-off = 0.15 (Annex A)
+ * == 1 means roll-off = 0.13 (Annex C)
+ */
+ reg0x3d = tda10021_readreg (state, 0x3d);
+ if (is_annex_c)
+ _tda10021_writereg (state, 0x3d, 0x01 | reg0x3d);
+ else
+ _tda10021_writereg (state, 0x3d, 0xfe & reg0x3d);
+ tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion);
return 0;
}
@@ -347,8 +386,9 @@ static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int tda10021_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda10021_state* state = fe->demodulator_priv;
int sync;
s8 afc = 0;
@@ -360,17 +400,17 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" :
"DVB: TDA10021(%d): [AFC (%d) %dHz]\n",
state->frontend.dvb->num, afc,
- -((s32)p->u.qam.symbol_rate * afc) >> 10);
+ -((s32)p->symbol_rate * afc) >> 10);
}
p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF;
- p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+ p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
- p->u.qam.fec_inner = FEC_NONE;
+ p->fec_inner = FEC_NONE;
p->frequency = ((p->frequency + 31250) / 62500) * 62500;
if (sync & 2)
- p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
+ p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
return 0;
}
@@ -444,10 +484,9 @@ error:
}
static struct dvb_frontend_ops tda10021_ops = {
-
+ .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
.info = {
.name = "Philips TDA10021 DVB-C",
- .type = FE_QAM,
.frequency_stepsize = 62500,
.frequency_min = 47000000,
.frequency_max = 862000000,
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index a3c34eecdee9..ca1e0d54b69a 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -298,42 +298,80 @@ static int tda10023_init (struct dvb_frontend *fe)
return 0;
}
-static int tda10023_set_parameters (struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+struct qam_params {
+ u8 qam, lockthr, mseth, aref, agcrefnyq, eragnyq_thd;
+};
+
+static int tda10023_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
+ unsigned qam = c->modulation;
+ bool is_annex_c;
struct tda10023_state* state = fe->demodulator_priv;
-
- static int qamvals[6][6] = {
- // QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD
- { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM
- { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM
- { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM
- { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM
- { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM
- { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM
+ static const struct qam_params qam_params[] = {
+ /* Modulation QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD */
+ [QPSK] = { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c },
+ [QAM_16] = { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 },
+ [QAM_32] = { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 },
+ [QAM_64] = { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 },
+ [QAM_128] = { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c },
+ [QAM_256] = { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c },
};
- int qam = p->u.qam.modulation;
+ switch (delsys) {
+ case SYS_DVBC_ANNEX_A:
+ is_annex_c = false;
+ break;
+ case SYS_DVBC_ANNEX_C:
+ is_annex_c = true;
+ break;
+ default:
+ return -EINVAL;
+ }
- if (qam < 0 || qam > 5)
+ /*
+ * gcc optimizes the code bellow the same way as it would code:
+ * "if (qam > 5) return -EINVAL;"
+ * Yet, the code is clearer, as it shows what QAM standards are
+ * supported by the driver, and avoids the usage of magic numbers on
+ * it.
+ */
+ switch (qam) {
+ case QPSK:
+ case QAM_16:
+ case QAM_32:
+ case QAM_64:
+ case QAM_128:
+ case QAM_256:
+ break;
+ default:
return -EINVAL;
+ }
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- tda10023_set_symbolrate (state, p->u.qam.symbol_rate);
- tda10023_writereg (state, 0x05, qamvals[qam][1]);
- tda10023_writereg (state, 0x08, qamvals[qam][2]);
- tda10023_writereg (state, 0x09, qamvals[qam][3]);
- tda10023_writereg (state, 0xb4, qamvals[qam][4]);
- tda10023_writereg (state, 0xb6, qamvals[qam][5]);
-
-// tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32));
-// tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20));
- tda10023_writebit (state, 0x04, 0x40, 0x40);
- tda10023_setup_reg0 (state, qamvals[qam][0]);
+ tda10023_set_symbolrate(state, c->symbol_rate);
+ tda10023_writereg(state, 0x05, qam_params[qam].lockthr);
+ tda10023_writereg(state, 0x08, qam_params[qam].mseth);
+ tda10023_writereg(state, 0x09, qam_params[qam].aref);
+ tda10023_writereg(state, 0xb4, qam_params[qam].agcrefnyq);
+ tda10023_writereg(state, 0xb6, qam_params[qam].eragnyq_thd);
+#if 0
+ tda10023_writereg(state, 0x04, (c->inversion ? 0x12 : 0x32));
+ tda10023_writebit(state, 0x04, 0x60, (c->inversion ? 0 : 0x20));
+#endif
+ tda10023_writebit(state, 0x04, 0x40, 0x40);
+
+ if (is_annex_c)
+ tda10023_writebit(state, 0x3d, 0xfc, 0x03);
+ else
+ tda10023_writebit(state, 0x3d, 0xfc, 0x02);
+
+ tda10023_setup_reg0(state, qam_params[qam].qam);
return 0;
}
@@ -418,8 +456,9 @@ static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int tda10023_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda10023_state* state = fe->demodulator_priv;
int sync,inv;
s8 afc = 0;
@@ -433,17 +472,17 @@ static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" :
"DVB: TDA10023(%d): [AFC (%d) %dHz]\n",
state->frontend.dvb->num, afc,
- -((s32)p->u.qam.symbol_rate * afc) >> 10);
+ -((s32)p->symbol_rate * afc) >> 10);
}
p->inversion = (inv&0x20?0:1);
- p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+ p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
- p->u.qam.fec_inner = FEC_NONE;
+ p->fec_inner = FEC_NONE;
p->frequency = ((p->frequency + 31250) / 62500) * 62500;
if (sync & 2)
- p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
+ p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
return 0;
}
@@ -534,10 +573,9 @@ error:
}
static struct dvb_frontend_ops tda10023_ops = {
-
+ .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
.info = {
.name = "Philips TDA10023 DVB-C",
- .type = FE_QAM,
.frequency_stepsize = 62500,
.frequency_min = 47000000,
.frequency_max = 862000000,
@@ -557,7 +595,6 @@ static struct dvb_frontend_ops tda10023_ops = {
.set_frontend = tda10023_set_parameters,
.get_frontend = tda10023_get_frontend,
-
.read_status = tda10023_read_status,
.read_ber = tda10023_read_ber,
.read_signal_strength = tda10023_read_signal_strength,
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
index 7f105946a434..71fb63299de7 100644
--- a/drivers/media/dvb/frontends/tda10048.c
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -153,7 +153,7 @@ struct tda10048_state {
u32 pll_pfactor;
u32 sample_freq;
- enum fe_bandwidth bandwidth;
+ u32 bandwidth;
};
static struct init_tab {
@@ -341,21 +341,14 @@ static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz,
{
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;
+ t = bw * 10;
/* avoid warning: this decimal constant is unsigned only in ISO C90 */
/* t *= 2147483648 on 32bit platforms */
t *= (2048 * 1024);
@@ -378,25 +371,18 @@ static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
{
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);
+ do_div(t, bw);
t += 5;
do_div(t, 10);
@@ -407,16 +393,16 @@ static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
}
static int tda10048_set_bandwidth(struct dvb_frontend *fe,
- enum fe_bandwidth bw)
+ u32 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:
+ case 6000000:
+ case 7000000:
+ case 8000000:
tda10048_set_wref(fe, state->sample_freq, bw);
tda10048_set_invwref(fe, state->sample_freq, bw);
break;
@@ -430,7 +416,7 @@ static int tda10048_set_bandwidth(struct dvb_frontend *fe,
return 0;
}
-static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
+static int tda10048_set_if(struct dvb_frontend *fe, u32 bw)
{
struct tda10048_state *state = fe->demodulator_priv;
struct tda10048_config *config = &state->config;
@@ -441,13 +427,13 @@ static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
/* based on target bandwidth and clk we calculate pll factors */
switch (bw) {
- case BANDWIDTH_6_MHZ:
+ case 6000000:
if_freq_khz = config->dtv6_if_freq_khz;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
if_freq_khz = config->dtv7_if_freq_khz;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
if_freq_khz = config->dtv8_if_freq_khz;
break;
default:
@@ -601,7 +587,7 @@ static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion)
/* Retrieve the demod settings */
static int tda10048_get_tps(struct tda10048_state *state,
- struct dvb_ofdm_parameters *p)
+ struct dtv_frontend_properties *p)
{
u8 val;
@@ -612,27 +598,27 @@ static int tda10048_get_tps(struct tda10048_state *state,
val = tda10048_readreg(state, TDA10048_OUT_CONF2);
switch ((val & 0x60) >> 5) {
case 0:
- p->constellation = QPSK;
+ p->modulation = QPSK;
break;
case 1:
- p->constellation = QAM_16;
+ p->modulation = QAM_16;
break;
case 2:
- p->constellation = QAM_64;
+ p->modulation = QAM_64;
break;
}
switch ((val & 0x18) >> 3) {
case 0:
- p->hierarchy_information = HIERARCHY_NONE;
+ p->hierarchy = HIERARCHY_NONE;
break;
case 1:
- p->hierarchy_information = HIERARCHY_1;
+ p->hierarchy = HIERARCHY_1;
break;
case 2:
- p->hierarchy_information = HIERARCHY_2;
+ p->hierarchy = HIERARCHY_2;
break;
case 3:
- p->hierarchy_information = HIERARCHY_4;
+ p->hierarchy = HIERARCHY_4;
break;
}
switch (val & 0x07) {
@@ -738,17 +724,17 @@ static int tda10048_output_mode(struct dvb_frontend *fe, int serial)
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
/* TODO: Support manual tuning with specific params */
-static int tda10048_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int tda10048_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda10048_state *state = fe->demodulator_priv;
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 (p->bandwidth_hz != state->bandwidth) {
+ tda10048_set_if(fe, p->bandwidth_hz);
+ tda10048_set_bandwidth(fe, p->bandwidth_hz);
}
if (fe->ops.tuner_ops.set_params) {
@@ -756,7 +742,7 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
@@ -797,8 +783,8 @@ static int tda10048_init(struct dvb_frontend *fe)
tda10048_set_inversion(fe, config->inversion);
/* Establish default RF values */
- tda10048_set_if(fe, BANDWIDTH_8_MHZ);
- tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ);
+ tda10048_set_if(fe, 8000000);
+ tda10048_set_bandwidth(fe, 8000000);
/* Ensure we leave the gate closed */
tda10048_i2c_gate_ctrl(fe, 0);
@@ -1042,9 +1028,9 @@ static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
return 0;
}
-static int tda10048_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int tda10048_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda10048_state *state = fe->demodulator_priv;
dprintk(1, "%s()\n", __func__);
@@ -1052,7 +1038,7 @@ static int tda10048_get_frontend(struct dvb_frontend *fe,
p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1)
& 0x20 ? INVERSION_ON : INVERSION_OFF;
- return tda10048_get_tps(state, &p->u.ofdm);
+ return tda10048_get_tps(state, p);
}
static int tda10048_get_tune_settings(struct dvb_frontend *fe,
@@ -1126,7 +1112,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
memcpy(&state->config, config, sizeof(*config));
state->i2c = i2c;
state->fwloaded = config->no_firmware;
- state->bandwidth = BANDWIDTH_8_MHZ;
+ state->bandwidth = 8000000;
/* check if the demod is present */
if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
@@ -1152,11 +1138,11 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
tda10048_establish_defaults(&state->frontend);
/* Set the xtal and freq defaults */
- if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0)
+ if (tda10048_set_if(&state->frontend, 8000000) != 0)
goto error;
/* Default bandwidth */
- if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0)
+ if (tda10048_set_bandwidth(&state->frontend, 8000000) != 0)
goto error;
/* Leave the gate closed */
@@ -1171,10 +1157,9 @@ error:
EXPORT_SYMBOL(tda10048_attach);
static struct dvb_frontend_ops tda10048_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "NXP TDA10048HN DVB-T",
- .type = FE_OFDM,
.frequency_min = 177000000,
.frequency_max = 858000000,
.frequency_stepsize = 166666,
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index ea485d923550..35d72b46aa1e 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -224,22 +224,22 @@ static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state)
}
static int tda10045h_set_bandwidth(struct tda1004x_state *state,
- fe_bandwidth_t bandwidth)
+ u32 bandwidth)
{
static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
switch (bandwidth) {
- case BANDWIDTH_6_MHZ:
+ case 6000000:
tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
break;
@@ -253,7 +253,7 @@ static int tda10045h_set_bandwidth(struct tda1004x_state *state,
}
static int tda10046h_set_bandwidth(struct tda1004x_state *state,
- fe_bandwidth_t bandwidth)
+ u32 bandwidth)
{
static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
@@ -270,7 +270,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state,
else
tda10046_clk53m = 1;
switch (bandwidth) {
- case BANDWIDTH_6_MHZ:
+ case 6000000:
if (tda10046_clk53m)
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
sizeof(bandwidth_6mhz_53M));
@@ -283,7 +283,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state,
}
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
if (tda10046_clk53m)
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
sizeof(bandwidth_7mhz_53M));
@@ -296,7 +296,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state,
}
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
if (tda10046_clk53m)
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
sizeof(bandwidth_8mhz_53M));
@@ -409,7 +409,7 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
msleep(10);
/* set parameters */
- tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ);
+ tda10045h_set_bandwidth(state, 8000000);
ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
release_firmware(fw);
@@ -473,7 +473,7 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
break;
}
- tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
+ tda10046h_set_bandwidth(state, 8000000); /* default bandwidth 8 MHz */
/* let the PLLs settle */
msleep(120);
}
@@ -697,9 +697,9 @@ static int tda10046_init(struct dvb_frontend* fe)
return 0;
}
-static int tda1004x_set_fe(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fe_params)
+static int tda1004x_set_fe(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
struct tda1004x_state* state = fe->demodulator_priv;
int tmp;
int inversion;
@@ -718,7 +718,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
// set frequency
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, fe_params);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
@@ -726,37 +726,37 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
// Hardcoded to use auto as much as possible on the TDA10045 as it
// is very unreliable if AUTO mode is _not_ used.
if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
- fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
- fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
- fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+ fe_params->code_rate_HP = FEC_AUTO;
+ fe_params->guard_interval = GUARD_INTERVAL_AUTO;
+ fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
}
// Set standard params.. or put them to auto
- if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
- (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
- (fe_params->u.ofdm.constellation == QAM_AUTO) ||
- (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
+ if ((fe_params->code_rate_HP == FEC_AUTO) ||
+ (fe_params->code_rate_LP == FEC_AUTO) ||
+ (fe_params->modulation == QAM_AUTO) ||
+ (fe_params->hierarchy == HIERARCHY_AUTO)) {
tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto
- tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); /* turn off modulation bits */
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits
tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits
} else {
tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto
// set HP FEC
- tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP);
+ tmp = tda1004x_encode_fec(fe_params->code_rate_HP);
if (tmp < 0)
return tmp;
tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
// set LP FEC
- tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
+ tmp = tda1004x_encode_fec(fe_params->code_rate_LP);
if (tmp < 0)
return tmp;
tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
- // set constellation
- switch (fe_params->u.ofdm.constellation) {
+ /* set modulation */
+ switch (fe_params->modulation) {
case QPSK:
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0);
break;
@@ -774,7 +774,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
}
// set hierarchy
- switch (fe_params->u.ofdm.hierarchy_information) {
+ switch (fe_params->hierarchy) {
case HIERARCHY_NONE:
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
break;
@@ -799,11 +799,11 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
// set bandwidth
switch (state->demod_type) {
case TDA1004X_DEMOD_TDA10045:
- tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
+ tda10045h_set_bandwidth(state, fe_params->bandwidth_hz);
break;
case TDA1004X_DEMOD_TDA10046:
- tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
+ tda10046h_set_bandwidth(state, fe_params->bandwidth_hz);
break;
}
@@ -825,7 +825,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
}
// set guard interval
- switch (fe_params->u.ofdm.guard_interval) {
+ switch (fe_params->guard_interval) {
case GUARD_INTERVAL_1_32:
tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
@@ -856,7 +856,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
}
// set transmission mode
- switch (fe_params->u.ofdm.transmission_mode) {
+ switch (fe_params->transmission_mode) {
case TRANSMISSION_MODE_2K:
tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
@@ -895,8 +895,9 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
return 0;
}
-static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
+static int tda1004x_get_fe(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
struct tda1004x_state* state = fe->demodulator_priv;
dprintk("%s\n", __func__);
@@ -913,13 +914,13 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
case TDA1004X_DEMOD_TDA10045:
switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
case 0x14:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ fe_params->bandwidth_hz = 8000000;
break;
case 0xdb:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ fe_params->bandwidth_hz = 7000000;
break;
case 0x4f:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ fe_params->bandwidth_hz = 6000000;
break;
}
break;
@@ -927,73 +928,73 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
case 0x5c:
case 0x54:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ fe_params->bandwidth_hz = 8000000;
break;
case 0x6a:
case 0x60:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ fe_params->bandwidth_hz = 7000000;
break;
case 0x7b:
case 0x70:
- fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ fe_params->bandwidth_hz = 6000000;
break;
}
break;
}
// FEC
- fe_params->u.ofdm.code_rate_HP =
+ fe_params->code_rate_HP =
tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7);
- fe_params->u.ofdm.code_rate_LP =
+ fe_params->code_rate_LP =
tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7);
- // constellation
+ /* modulation */
switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) {
case 0:
- fe_params->u.ofdm.constellation = QPSK;
+ fe_params->modulation = QPSK;
break;
case 1:
- fe_params->u.ofdm.constellation = QAM_16;
+ fe_params->modulation = QAM_16;
break;
case 2:
- fe_params->u.ofdm.constellation = QAM_64;
+ fe_params->modulation = QAM_64;
break;
}
// transmission mode
- fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+ fe_params->transmission_mode = TRANSMISSION_MODE_2K;
if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10)
- fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ fe_params->transmission_mode = TRANSMISSION_MODE_8K;
// guard interval
switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
case 0:
- fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ fe_params->guard_interval = GUARD_INTERVAL_1_32;
break;
case 1:
- fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+ fe_params->guard_interval = GUARD_INTERVAL_1_16;
break;
case 2:
- fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+ fe_params->guard_interval = GUARD_INTERVAL_1_8;
break;
case 3:
- fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+ fe_params->guard_interval = GUARD_INTERVAL_1_4;
break;
}
// hierarchy
switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) {
case 0:
- fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ fe_params->hierarchy = HIERARCHY_NONE;
break;
case 1:
- fe_params->u.ofdm.hierarchy_information = HIERARCHY_1;
+ fe_params->hierarchy = HIERARCHY_1;
break;
case 2:
- fe_params->u.ofdm.hierarchy_information = HIERARCHY_2;
+ fe_params->hierarchy = HIERARCHY_2;
break;
case 3:
- fe_params->u.ofdm.hierarchy_information = HIERARCHY_4;
+ fe_params->hierarchy = HIERARCHY_4;
break;
}
@@ -1231,9 +1232,9 @@ static void tda1004x_release(struct dvb_frontend* fe)
}
static struct dvb_frontend_ops tda10045_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "Philips TDA10045H DVB-T",
- .type = FE_OFDM,
.frequency_min = 51000000,
.frequency_max = 858000000,
.frequency_stepsize = 166667,
@@ -1271,7 +1272,7 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
if (!state) {
- printk(KERN_ERR "Can't alocate memory for tda10045 state\n");
+ printk(KERN_ERR "Can't allocate memory for tda10045 state\n");
return NULL;
}
@@ -1301,9 +1302,9 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
}
static struct dvb_frontend_ops tda10046_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "Philips TDA10046H DVB-T",
- .type = FE_OFDM,
.frequency_min = 51000000,
.frequency_max = 858000000,
.frequency_stepsize = 166667,
@@ -1341,7 +1342,7 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
if (!state) {
- printk(KERN_ERR "Can't alocate memory for tda10046 state\n");
+ printk(KERN_ERR "Can't allocate memory for tda10046 state\n");
return NULL;
}
diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c
index 0c37434d19e2..c21bc92d2811 100644
--- a/drivers/media/dvb/frontends/tda10071.c
+++ b/drivers/media/dvb/frontends/tda10071.c
@@ -636,8 +636,7 @@ error:
return ret;
}
-static int tda10071_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int tda10071_set_frontend(struct dvb_frontend *fe)
{
struct tda10071_priv *priv = fe->demodulator_priv;
struct tda10071_cmd cmd;
@@ -777,8 +776,7 @@ error:
return ret;
}
-static int tda10071_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int tda10071_get_frontend(struct dvb_frontend *fe)
{
struct tda10071_priv *priv = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -1217,9 +1215,9 @@ error:
EXPORT_SYMBOL(tda10071_attach);
static struct dvb_frontend_ops tda10071_ops = {
+ .delsys = { SYS_DVBS, SYS_DVBS2 },
.info = {
.name = "NXP TDA10071",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_tolerance = 5000,
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
index f2c8faac6f36..fcfe2e080cb0 100644
--- a/drivers/media/dvb/frontends/tda10086.c
+++ b/drivers/media/dvb/frontends/tda10086.c
@@ -267,7 +267,7 @@ static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minic
}
static int tda10086_set_inversion(struct tda10086_state *state,
- struct dvb_frontend_parameters *fe_params)
+ struct dtv_frontend_properties *fe_params)
{
u8 invval = 0x80;
@@ -292,7 +292,7 @@ static int tda10086_set_inversion(struct tda10086_state *state,
}
static int tda10086_set_symbol_rate(struct tda10086_state *state,
- struct dvb_frontend_parameters *fe_params)
+ struct dtv_frontend_properties *fe_params)
{
u8 dfn = 0;
u8 afs = 0;
@@ -303,7 +303,7 @@ static int tda10086_set_symbol_rate(struct tda10086_state *state,
u32 tmp;
u32 bdr;
u32 bdri;
- u32 symbol_rate = fe_params->u.qpsk.symbol_rate;
+ u32 symbol_rate = fe_params->symbol_rate;
dprintk ("%s %i\n", __func__, symbol_rate);
@@ -367,13 +367,13 @@ static int tda10086_set_symbol_rate(struct tda10086_state *state,
}
static int tda10086_set_fec(struct tda10086_state *state,
- struct dvb_frontend_parameters *fe_params)
+ struct dtv_frontend_properties *fe_params)
{
u8 fecval;
- dprintk ("%s %i\n", __func__, fe_params->u.qpsk.fec_inner);
+ dprintk("%s %i\n", __func__, fe_params->fec_inner);
- switch(fe_params->u.qpsk.fec_inner) {
+ switch (fe_params->fec_inner) {
case FEC_1_2:
fecval = 0x00;
break;
@@ -409,9 +409,9 @@ static int tda10086_set_fec(struct tda10086_state *state,
return 0;
}
-static int tda10086_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fe_params)
+static int tda10086_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
struct tda10086_state *state = fe->demodulator_priv;
int ret;
u32 freq = 0;
@@ -425,7 +425,7 @@ static int tda10086_set_frontend(struct dvb_frontend* fe,
/* set params */
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, fe_params);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
@@ -452,13 +452,14 @@ static int tda10086_set_frontend(struct dvb_frontend* fe,
tda10086_write_mask(state, 0x10, 0x40, 0x40);
tda10086_write_mask(state, 0x00, 0x01, 0x00);
- state->symbol_rate = fe_params->u.qpsk.symbol_rate;
+ state->symbol_rate = fe_params->symbol_rate;
state->frequency = fe_params->frequency;
return 0;
}
-static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
+static int tda10086_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
struct tda10086_state* state = fe->demodulator_priv;
u8 val;
int tmp;
@@ -467,7 +468,7 @@ static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
dprintk ("%s\n", __func__);
/* check for invalid symbol rate */
- if (fe_params->u.qpsk.symbol_rate < 500000)
+ if (fe_params->symbol_rate < 500000)
return -EINVAL;
/* calculate the updated frequency (note: we convert from Hz->kHz) */
@@ -516,34 +517,34 @@ static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
tmp |= 0xffffff00;
tmp = (tmp * 480 * (1<<1)) / 128;
tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000);
- fe_params->u.qpsk.symbol_rate = state->symbol_rate + tmp;
+ fe_params->symbol_rate = state->symbol_rate + tmp;
/* the FEC */
val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4;
switch(val) {
case 0x00:
- fe_params->u.qpsk.fec_inner = FEC_1_2;
+ fe_params->fec_inner = FEC_1_2;
break;
case 0x01:
- fe_params->u.qpsk.fec_inner = FEC_2_3;
+ fe_params->fec_inner = FEC_2_3;
break;
case 0x02:
- fe_params->u.qpsk.fec_inner = FEC_3_4;
+ fe_params->fec_inner = FEC_3_4;
break;
case 0x03:
- fe_params->u.qpsk.fec_inner = FEC_4_5;
+ fe_params->fec_inner = FEC_4_5;
break;
case 0x04:
- fe_params->u.qpsk.fec_inner = FEC_5_6;
+ fe_params->fec_inner = FEC_5_6;
break;
case 0x05:
- fe_params->u.qpsk.fec_inner = FEC_6_7;
+ fe_params->fec_inner = FEC_6_7;
break;
case 0x06:
- fe_params->u.qpsk.fec_inner = FEC_7_8;
+ fe_params->fec_inner = FEC_7_8;
break;
case 0x07:
- fe_params->u.qpsk.fec_inner = FEC_8_9;
+ fe_params->fec_inner = FEC_8_9;
break;
}
@@ -664,29 +665,31 @@ static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
static int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
- if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+ if (p->symbol_rate > 20000000) {
fesettings->min_delay_ms = 50;
fesettings->step_size = 2000;
fesettings->max_drift = 8000;
- } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
+ } else if (p->symbol_rate > 12000000) {
fesettings->min_delay_ms = 100;
fesettings->step_size = 1500;
fesettings->max_drift = 9000;
- } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
+ } else if (p->symbol_rate > 8000000) {
fesettings->min_delay_ms = 100;
fesettings->step_size = 1000;
fesettings->max_drift = 8000;
- } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
+ } else if (p->symbol_rate > 4000000) {
fesettings->min_delay_ms = 100;
fesettings->step_size = 500;
fesettings->max_drift = 7000;
- } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
+ } else if (p->symbol_rate > 2000000) {
fesettings->min_delay_ms = 200;
- fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+ fesettings->step_size = p->symbol_rate / 8000;
fesettings->max_drift = 14 * fesettings->step_size;
} else {
fesettings->min_delay_ms = 200;
- fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+ fesettings->step_size = p->symbol_rate / 8000;
fesettings->max_drift = 18 * fesettings->step_size;
}
@@ -701,10 +704,9 @@ static void tda10086_release(struct dvb_frontend* fe)
}
static struct dvb_frontend_ops tda10086_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "Philips TDA10086 DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 125, /* kHz for QPSK frontends */
diff --git a/drivers/media/dvb/frontends/tda18271c2dd.c b/drivers/media/dvb/frontends/tda18271c2dd.c
index 1b1bf200c55c..ad7c72e8f517 100644
--- a/drivers/media/dvb/frontends/tda18271c2dd.c
+++ b/drivers/media/dvb/frontends/tda18271c2dd.c
@@ -29,7 +29,6 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
-#include <linux/version.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
@@ -1123,55 +1122,51 @@ static int release(struct dvb_frontend *fe)
return 0;
}
-/*
- * As defined on EN 300 429 Annex A and on ITU-T J.83 annex A, the DVB-C
- * roll-off factor is 0.15.
- * According with the specs, the amount of the needed bandwith is given by:
- * Bw = Symbol_rate * (1 + 0.15)
- * As such, the maximum symbol rate supported by 6 MHz is
- * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
- *NOTE: For ITU-T J.83 Annex C, the roll-off factor is 0.13. So:
- * max_symbol_rate = 6 MHz / 1.13 = 5309735 Baud
- * That means that an adjustment is needed for Japan,
- * but, as currently DRX-K is hardcoded to Annex A, let's stick
- * with 0.15 roll-off factor.
- */
-#define MAX_SYMBOL_RATE_6MHz 5217391
-static int set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int set_params(struct dvb_frontend *fe)
{
struct tda_state *state = fe->tuner_priv;
int status = 0;
int Standard;
+ u32 bw = fe->dtv_property_cache.bandwidth_hz;
+ u32 delsys = fe->dtv_property_cache.delivery_system;
- state->m_Frequency = params->frequency;
+ state->m_Frequency = fe->dtv_property_cache.frequency;
- if (fe->ops.info.type == FE_OFDM)
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (delsys) {
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ switch (bw) {
+ case 6000000:
Standard = HF_DVBT_6MHZ;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
Standard = HF_DVBT_7MHZ;
break;
- default:
- case BANDWIDTH_8_MHZ:
+ case 8000000:
Standard = HF_DVBT_8MHZ;
break;
+ default:
+ return -EINVAL;
}
- else if (fe->ops.info.type == FE_QAM) {
- if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz)
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
+ if (bw <= 6000000)
Standard = HF_DVBC_6MHZ;
+ else if (bw <= 7000000)
+ Standard = HF_DVBC_7MHZ;
else
Standard = HF_DVBC_8MHZ;
- } else
+ break;
+ default:
return -EINVAL;
+ }
do {
- status = RFTrackingFiltersCorrection(state, params->frequency);
+ status = RFTrackingFiltersCorrection(state, state->m_Frequency);
if (status < 0)
break;
- status = ChannelConfiguration(state, params->frequency, Standard);
+ status = ChannelConfiguration(state, state->m_Frequency,
+ Standard);
if (status < 0)
break;
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index 9369f7442f27..15912c96926a 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -315,18 +315,19 @@ static int tda8083_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int tda8083_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda8083_state* state = fe->demodulator_priv;
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
tda8083_set_inversion (state, p->inversion);
- tda8083_set_fec (state, p->u.qpsk.fec_inner);
- tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate);
+ tda8083_set_fec(state, p->fec_inner);
+ tda8083_set_symbolrate(state, p->symbol_rate);
tda8083_writereg (state, 0x00, 0x3c);
tda8083_writereg (state, 0x00, 0x04);
@@ -334,16 +335,17 @@ static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
return 0;
}
-static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int tda8083_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda8083_state* state = fe->demodulator_priv;
/* FIXME: get symbolrate & frequency offset...*/
/*p->frequency = ???;*/
p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ?
INVERSION_ON : INVERSION_OFF;
- p->u.qpsk.fec_inner = tda8083_get_fec (state);
- /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (state);*/
+ p->fec_inner = tda8083_get_fec(state);
+ /*p->symbol_rate = tda8083_get_symbolrate (state);*/
return 0;
}
@@ -438,10 +440,9 @@ error:
}
static struct dvb_frontend_ops tda8083_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "Philips TDA8083 DVB-S",
- .type = FE_QPSK,
.frequency_min = 920000, /* TDA8060 */
.frequency_max = 2200000, /* TDA8060 */
.frequency_stepsize = 125, /* kHz for QPSK frontends */
diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c
index 06c94800b940..04bbcc24de0a 100644
--- a/drivers/media/dvb/frontends/tda826x.c
+++ b/drivers/media/dvb/frontends/tda826x.c
@@ -71,8 +71,9 @@ static int tda826x_sleep(struct dvb_frontend *fe)
return (ret == 1) ? 0 : ret;
}
-static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tda826x_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct tda826x_priv *priv = fe->tuner_priv;
int ret;
u32 div;
@@ -83,11 +84,11 @@ static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_param
dprintk("%s:\n", __func__);
- div = (params->frequency + (1000-1)) / 1000;
+ div = (p->frequency + (1000-1)) / 1000;
/* BW = ((1 + RO) * SR/2 + 5) * 1.3 [SR in MSPS, BW in MHz] */
/* with R0 = 0.35 and some transformations: */
- ksyms = params->u.qpsk.symbol_rate / 1000;
+ ksyms = p->symbol_rate / 1000;
bandwidth = (878 * ksyms + 6500000) / 1000000 + 1;
if (bandwidth < 5)
bandwidth = 5;
diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb/frontends/tdhd1.h
index 51f170678650..17750985db0c 100644
--- a/drivers/media/dvb/frontends/tdhd1.h
+++ b/drivers/media/dvb/frontends/tdhd1.h
@@ -40,24 +40,25 @@ static struct tda1004x_config alps_tdhd1_204a_config = {
.request_firmware = alps_tdhd1_204_request_firmware
};
-static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct i2c_adapter *i2c = fe->tuner_priv;
u8 data[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
u32 div;
- div = (params->frequency + 36166666) / 166666;
+ div = (p->frequency + 36166666) / 166666;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = 0x85;
- if (params->frequency >= 174000000 && params->frequency <= 230000000)
+ if (p->frequency >= 174000000 && p->frequency <= 230000000)
data[3] = 0x02;
- else if (params->frequency >= 470000000 && params->frequency <= 823000000)
+ else if (p->frequency >= 470000000 && p->frequency <= 823000000)
data[3] = 0x0C;
- else if (params->frequency > 823000000 && params->frequency <= 862000000)
+ else if (p->frequency > 823000000 && p->frequency <= 862000000)
data[3] = 0x8C;
else
return -EINVAL;
diff --git a/drivers/media/dvb/frontends/tua6100.c b/drivers/media/dvb/frontends/tua6100.c
index bcb95c2ef296..029384d1fddd 100644
--- a/drivers/media/dvb/frontends/tua6100.c
+++ b/drivers/media/dvb/frontends/tua6100.c
@@ -67,9 +67,9 @@ static int tua6100_sleep(struct dvb_frontend *fe)
return (ret == 1) ? 0 : ret;
}
-static int tua6100_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int tua6100_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct tua6100_priv *priv = fe->tuner_priv;
u32 div;
u32 prediv;
@@ -85,36 +85,37 @@ static int tua6100_set_params(struct dvb_frontend *fe,
#define _ri 4000000
// setup register 0
- if (params->frequency < 2000000) {
+ if (c->frequency < 2000000)
reg0[1] = 0x03;
- } else {
+ else
reg0[1] = 0x07;
- }
// setup register 1
- if (params->frequency < 1630000) {
+ if (c->frequency < 1630000)
reg1[1] = 0x2c;
- } else {
+ else
reg1[1] = 0x0c;
- }
+
if (_P == 64)
reg1[1] |= 0x40;
- if (params->frequency >= 1525000)
+ if (c->frequency >= 1525000)
reg1[1] |= 0x80;
// register 2
reg2[1] = (_R >> 8) & 0x03;
reg2[2] = _R;
- if (params->frequency < 1455000) {
+ if (c->frequency < 1455000)
reg2[1] |= 0x1c;
- } else if (params->frequency < 1630000) {
+ else if (c->frequency < 1630000)
reg2[1] |= 0x0c;
- } else {
+ else
reg2[1] |= 0x1c;
- }
- // The N divisor ratio (note: params->frequency is in kHz, but we need it in Hz)
- prediv = (params->frequency * _R) / (_ri / 1000);
+ /*
+ * The N divisor ratio (note: c->frequency is in kHz, but we
+ * need it in Hz)
+ */
+ prediv = (c->frequency * _R) / (_ri / 1000);
div = prediv / _P;
reg1[1] |= (div >> 9) & 0x03;
reg1[2] = div >> 1;
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index 550a07a8a997..bb42b563c42d 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -205,25 +205,26 @@ static int ves1820_init(struct dvb_frontend* fe)
return 0;
}
-static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ves1820_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ves1820_state* state = fe->demodulator_priv;
static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
static const u8 reg0x01[] = { 140, 140, 106, 100, 92 };
static const u8 reg0x05[] = { 135, 100, 70, 54, 38 };
static const u8 reg0x08[] = { 162, 116, 67, 52, 35 };
static const u8 reg0x09[] = { 145, 150, 106, 126, 107 };
- int real_qam = p->u.qam.modulation - QAM_16;
+ int real_qam = p->modulation - QAM_16;
if (real_qam < 0 || real_qam > 4)
return -EINVAL;
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
+ ves1820_set_symbolrate(state, p->symbol_rate);
ves1820_writereg(state, 0x34, state->pwm);
ves1820_writereg(state, 0x01, reg0x01[real_qam]);
@@ -309,8 +310,9 @@ static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ves1820_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ves1820_state* state = fe->demodulator_priv;
int sync;
s8 afc = 0;
@@ -320,7 +322,7 @@ static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
if (verbose) {
/* AFC only valid when carrier has been recovered */
printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
- "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10);
+ "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->symbol_rate * afc) >> 10);
}
if (!state->config->invert) {
@@ -329,13 +331,13 @@ static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF;
}
- p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+ p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
- p->u.qam.fec_inner = FEC_NONE;
+ p->fec_inner = FEC_NONE;
p->frequency = ((p->frequency + 31250) / 62500) * 62500;
if (sync & 2)
- p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10;
+ p->frequency -= ((s32) p->symbol_rate * afc) >> 10;
return 0;
}
@@ -405,10 +407,9 @@ error:
}
static struct dvb_frontend_ops ves1820_ops = {
-
+ .delsys = { SYS_DVBC_ANNEX_A },
.info = {
.name = "VLSI VES1820 DVB-C",
- .type = FE_QAM,
.frequency_stepsize = 62500,
.frequency_min = 47000000,
.frequency_max = 862000000,
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 8d7854c2fb0c..9c17eacaec24 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -46,6 +46,7 @@ struct ves1x93_state {
u8 *init_1x93_wtab;
u8 tab_size;
u8 demod_type;
+ u32 frequency;
};
static int debug;
@@ -384,31 +385,34 @@ static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
-static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ves1x93_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ves1x93_state* state = fe->demodulator_priv;
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, p);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
ves1x93_set_inversion (state, p->inversion);
- ves1x93_set_fec (state, p->u.qpsk.fec_inner);
- ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
+ ves1x93_set_fec(state, p->fec_inner);
+ ves1x93_set_symbolrate(state, p->symbol_rate);
state->inversion = p->inversion;
+ state->frequency = p->frequency;
return 0;
}
-static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ves1x93_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ves1x93_state* state = fe->demodulator_priv;
int afc;
afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2;
- afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16;
+ afc = (afc * (int)(p->symbol_rate/1000/8))/16;
- p->frequency -= afc;
+ p->frequency = state->frequency - afc;
/*
* inversion indicator is only valid
@@ -417,7 +421,7 @@ static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
if (state->inversion == INVERSION_AUTO)
p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ?
INVERSION_OFF : INVERSION_ON;
- p->u.qpsk.fec_inner = ves1x93_get_fec (state);
+ p->fec_inner = ves1x93_get_fec(state);
/* XXX FIXME: timing offset !! */
return 0;
@@ -506,10 +510,9 @@ error:
}
static struct dvb_frontend_ops ves1x93_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "VLSI VES1x93 DVB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 125, /* kHz for QPSK frontends */
diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb/frontends/zl10036.c
index 81aa984c551f..0903d461b8fa 100644
--- a/drivers/media/dvb/frontends/zl10036.c
+++ b/drivers/media/dvb/frontends/zl10036.c
@@ -305,12 +305,12 @@ static int zl10036_set_gain_params(struct zl10036_state *state,
return zl10036_write(state, buf, sizeof(buf));
}
-static int zl10036_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int zl10036_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct zl10036_state *state = fe->tuner_priv;
int ret = 0;
- u32 frequency = params->frequency;
+ u32 frequency = p->frequency;
u32 fbw;
int i;
u8 c;
@@ -326,7 +326,7 @@ static int zl10036_set_params(struct dvb_frontend *fe,
* fBW = (alpha*symbolrate)/(2*0.8)
* 1.35 / (2*0.8) = 27 / 32
*/
- fbw = (27 * params->u.qpsk.symbol_rate) / 32;
+ fbw = (27 * p->symbol_rate) / 32;
/* scale to kHz */
fbw /= 1000;
@@ -353,7 +353,7 @@ static int zl10036_set_params(struct dvb_frontend *fe,
if (ret < 0)
goto error;
- ret = zl10036_set_frequency(state, params->frequency);
+ ret = zl10036_set_frequency(state, p->frequency);
if (ret < 0)
goto error;
diff --git a/drivers/media/dvb/frontends/zl10039.c b/drivers/media/dvb/frontends/zl10039.c
index c085e58a94bf..eff9c5fde50a 100644
--- a/drivers/media/dvb/frontends/zl10039.c
+++ b/drivers/media/dvb/frontends/zl10039.c
@@ -176,9 +176,9 @@ static int zl10039_sleep(struct dvb_frontend *fe)
return 0;
}
-static int zl10039_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int zl10039_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct zl10039_state *state = fe->tuner_priv;
u8 buf[6];
u8 bf;
@@ -188,12 +188,12 @@ static int zl10039_set_params(struct dvb_frontend *fe,
dprintk("%s\n", __func__);
dprintk("Set frequency = %d, symbol rate = %d\n",
- params->frequency, params->u.qpsk.symbol_rate);
+ c->frequency, c->symbol_rate);
/* Assumed 10.111 MHz crystal oscillator */
/* Cancelled num/den 80 to prevent overflow */
- div = (params->frequency * 1000) / 126387;
- fbw = (params->u.qpsk.symbol_rate * 27) / 32000;
+ div = (c->frequency * 1000) / 126387;
+ fbw = (c->symbol_rate * 27) / 32000;
/* Cancelled num/den 10 to prevent overflow */
bf = ((fbw * 5088) / 1011100) - 1;
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index adbbf6d3d044..ac7237891374 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -37,9 +37,9 @@ struct zl10353_state {
struct zl10353_config config;
- enum fe_bandwidth bandwidth;
- u32 ucblocks;
- u32 frequency;
+ u32 bandwidth;
+ u32 ucblocks;
+ u32 frequency;
};
static int debug;
@@ -122,30 +122,17 @@ static void zl10353_dump_regs(struct dvb_frontend *fe)
}
static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
- enum fe_bandwidth bandwidth,
+ u32 bandwidth,
u16 *nominal_rate)
{
struct zl10353_state *state = fe->demodulator_priv;
u32 adc_clock = 450560; /* 45.056 MHz */
u64 value;
- u8 bw;
+ u8 bw = bandwidth / 1000000;
if (state->config.adc_clock)
adc_clock = state->config.adc_clock;
- switch (bandwidth) {
- case BANDWIDTH_6_MHZ:
- bw = 6;
- break;
- case BANDWIDTH_7_MHZ:
- bw = 7;
- break;
- case BANDWIDTH_8_MHZ:
- default:
- bw = 8;
- break;
- }
-
value = (u64)10 * (1 << 23) / 7 * 125;
value = (bw * value) + adc_clock / 2;
do_div(value, adc_clock);
@@ -192,16 +179,15 @@ static int zl10353_sleep(struct dvb_frontend *fe)
return 0;
}
-static int zl10353_set_parameters(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int zl10353_set_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct zl10353_state *state = fe->demodulator_priv;
u16 nominal_rate, input_freq;
u8 pllbuf[6] = { 0x67 }, acq_ctl = 0;
u16 tps = 0;
- struct dvb_ofdm_parameters *op = &param->u.ofdm;
- state->frequency = param->frequency;
+ state->frequency = c->frequency;
zl10353_single_write(fe, RESET, 0x80);
udelay(200);
@@ -211,42 +197,44 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
zl10353_single_write(fe, AGC_TARGET, 0x28);
- if (op->transmission_mode != TRANSMISSION_MODE_AUTO)
+ if (c->transmission_mode != TRANSMISSION_MODE_AUTO)
acq_ctl |= (1 << 0);
- if (op->guard_interval != GUARD_INTERVAL_AUTO)
+ if (c->guard_interval != GUARD_INTERVAL_AUTO)
acq_ctl |= (1 << 1);
zl10353_single_write(fe, ACQ_CTL, acq_ctl);
- switch (op->bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (c->bandwidth_hz) {
+ case 6000000:
/* These are extrapolated from the 7 and 8MHz values */
zl10353_single_write(fe, MCLK_RATIO, 0x97);
zl10353_single_write(fe, 0x64, 0x34);
zl10353_single_write(fe, 0xcc, 0xdd);
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
zl10353_single_write(fe, MCLK_RATIO, 0x86);
zl10353_single_write(fe, 0x64, 0x35);
zl10353_single_write(fe, 0xcc, 0x73);
break;
- case BANDWIDTH_8_MHZ:
default:
+ c->bandwidth_hz = 8000000;
+ /* fall though */
+ case 8000000:
zl10353_single_write(fe, MCLK_RATIO, 0x75);
zl10353_single_write(fe, 0x64, 0x36);
zl10353_single_write(fe, 0xcc, 0x73);
}
- zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate);
+ zl10353_calc_nominal_rate(fe, c->bandwidth_hz, &nominal_rate);
zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
- state->bandwidth = op->bandwidth;
+ state->bandwidth = c->bandwidth_hz;
zl10353_calc_input_freq(fe, &input_freq);
zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq));
zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq));
/* Hint at TPS settings */
- switch (op->code_rate_HP) {
+ switch (c->code_rate_HP) {
case FEC_2_3:
tps |= (1 << 7);
break;
@@ -266,7 +254,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
return -EINVAL;
}
- switch (op->code_rate_LP) {
+ switch (c->code_rate_LP) {
case FEC_2_3:
tps |= (1 << 4);
break;
@@ -283,14 +271,14 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
case FEC_AUTO:
break;
case FEC_NONE:
- if (op->hierarchy_information == HIERARCHY_AUTO ||
- op->hierarchy_information == HIERARCHY_NONE)
+ if (c->hierarchy == HIERARCHY_AUTO ||
+ c->hierarchy == HIERARCHY_NONE)
break;
default:
return -EINVAL;
}
- switch (op->constellation) {
+ switch (c->modulation) {
case QPSK:
break;
case QAM_AUTO:
@@ -304,7 +292,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
return -EINVAL;
}
- switch (op->transmission_mode) {
+ switch (c->transmission_mode) {
case TRANSMISSION_MODE_2K:
case TRANSMISSION_MODE_AUTO:
break;
@@ -315,7 +303,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
return -EINVAL;
}
- switch (op->guard_interval) {
+ switch (c->guard_interval) {
case GUARD_INTERVAL_1_32:
case GUARD_INTERVAL_AUTO:
break;
@@ -332,7 +320,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
return -EINVAL;
}
- switch (op->hierarchy_information) {
+ switch (c->hierarchy) {
case HIERARCHY_AUTO:
case HIERARCHY_NONE:
break;
@@ -362,12 +350,12 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
*/
if (state->config.no_tuner) {
if (fe->ops.tuner_ops.set_params) {
- fe->ops.tuner_ops.set_params(fe, param);
+ fe->ops.tuner_ops.set_params(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
} else if (fe->ops.tuner_ops.calc_regs) {
- fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5);
+ fe->ops.tuner_ops.calc_regs(fe, pllbuf + 1, 5);
pllbuf[1] <<= 1;
zl10353_write(fe, pllbuf, sizeof(pllbuf));
}
@@ -383,11 +371,10 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
return 0;
}
-static int zl10353_get_parameters(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int zl10353_get_parameters(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct zl10353_state *state = fe->demodulator_priv;
- struct dvb_ofdm_parameters *op = &param->u.ofdm;
int s6, s9;
u16 tps;
static const u8 tps_fec_to_api[8] = {
@@ -411,66 +398,66 @@ static int zl10353_get_parameters(struct dvb_frontend *fe,
tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 |
zl10353_read_register(state, TPS_RECEIVED_0);
- op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
- op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
+ c->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
+ c->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
switch ((tps >> 13) & 3) {
case 0:
- op->constellation = QPSK;
+ c->modulation = QPSK;
break;
case 1:
- op->constellation = QAM_16;
+ c->modulation = QAM_16;
break;
case 2:
- op->constellation = QAM_64;
+ c->modulation = QAM_64;
break;
default:
- op->constellation = QAM_AUTO;
+ c->modulation = QAM_AUTO;
break;
}
- op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
+ c->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
TRANSMISSION_MODE_2K;
switch ((tps >> 2) & 3) {
case 0:
- op->guard_interval = GUARD_INTERVAL_1_32;
+ c->guard_interval = GUARD_INTERVAL_1_32;
break;
case 1:
- op->guard_interval = GUARD_INTERVAL_1_16;
+ c->guard_interval = GUARD_INTERVAL_1_16;
break;
case 2:
- op->guard_interval = GUARD_INTERVAL_1_8;
+ c->guard_interval = GUARD_INTERVAL_1_8;
break;
case 3:
- op->guard_interval = GUARD_INTERVAL_1_4;
+ c->guard_interval = GUARD_INTERVAL_1_4;
break;
default:
- op->guard_interval = GUARD_INTERVAL_AUTO;
+ c->guard_interval = GUARD_INTERVAL_AUTO;
break;
}
switch ((tps >> 10) & 7) {
case 0:
- op->hierarchy_information = HIERARCHY_NONE;
+ c->hierarchy = HIERARCHY_NONE;
break;
case 1:
- op->hierarchy_information = HIERARCHY_1;
+ c->hierarchy = HIERARCHY_1;
break;
case 2:
- op->hierarchy_information = HIERARCHY_2;
+ c->hierarchy = HIERARCHY_2;
break;
case 3:
- op->hierarchy_information = HIERARCHY_4;
+ c->hierarchy = HIERARCHY_4;
break;
default:
- op->hierarchy_information = HIERARCHY_AUTO;
+ c->hierarchy = HIERARCHY_AUTO;
break;
}
- param->frequency = state->frequency;
- op->bandwidth = state->bandwidth;
- param->inversion = INVERSION_AUTO;
+ c->frequency = state->frequency;
+ c->bandwidth_hz = state->bandwidth;
+ c->inversion = INVERSION_AUTO;
return 0;
}
@@ -651,10 +638,9 @@ error:
}
static struct dvb_frontend_ops zl10353_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "Zarlink ZL10353 DVB-T",
- .type = FE_OFDM,
.frequency_min = 174000000,
.frequency_max = 862000000,
.frequency_stepsize = 166667,
diff --git a/drivers/media/dvb/mantis/mantis_hif.c b/drivers/media/dvb/mantis/mantis_hif.c
index 672cf4d2462d..10c68df7e16f 100644
--- a/drivers/media/dvb/mantis/mantis_hif.c
+++ b/drivers/media/dvb/mantis/mantis_hif.c
@@ -76,7 +76,7 @@ static int mantis_hif_write_wait(struct mantis_ca *ca)
udelay(500);
timeout++;
if (timeout > 100) {
- dprintk(MANTIS_ERROR, 1, "Adater(%d) Slot(0): Write operation timed out!", mantis->num);
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write operation timed out!", mantis->num);
rc = -ETIMEDOUT;
break;
}
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c
index 2ae0afa7756b..ad013e93ed11 100644
--- a/drivers/media/dvb/mantis/mantis_vp1033.c
+++ b/drivers/media/dvb/mantis/mantis_vp1033.c
@@ -83,9 +83,9 @@ u8 lgtdqcs001f_inittab[] = {
#define MANTIS_MODEL_NAME "VP-1033"
#define MANTIS_DEV_TYPE "DVB-S/DSS"
-int lgtdqcs001f_tuner_set(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+int lgtdqcs001f_tuner_set(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mantis_pci *mantis = fe->dvb->priv;
struct i2c_adapter *adapter = &mantis->adapter;
@@ -95,14 +95,14 @@ int lgtdqcs001f_tuner_set(struct dvb_frontend *fe,
struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)};
- div = params->frequency / 250;
+ div = p->frequency / 250;
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
buf[2] = 0x83;
buf[3] = 0xc0;
- if (params->frequency < 1531000)
+ if (p->frequency < 1531000)
buf[3] |= 0x04;
else
buf[3] &= ~0x04;
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c
index 06da0ddf05a7..1ca6837fbe46 100644
--- a/drivers/media/dvb/mantis/mantis_vp2033.c
+++ b/drivers/media/dvb/mantis/mantis_vp2033.c
@@ -65,8 +65,9 @@ static u8 read_pwm(struct mantis_pci *mantis)
return pwm;
}
-static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mantis_pci *mantis = fe->dvb->priv;
struct i2c_adapter *adapter = &mantis->adapter;
@@ -77,13 +78,13 @@ static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_fronten
#define CU1216_IF 36125000
#define TUNER_MUL 62500
- u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+ u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
buf[2] = 0xce;
- buf[3] = (params->frequency < 150000000 ? 0x01 :
- params->frequency < 445000000 ? 0x02 : 0x04);
+ buf[3] = (p->frequency < 150000000 ? 0x01 :
+ p->frequency < 445000000 ? 0x02 : 0x04);
buf[4] = 0xde;
buf[5] = 0x20;
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c
index f72b137b7652..d480741afd78 100644
--- a/drivers/media/dvb/mantis/mantis_vp2040.c
+++ b/drivers/media/dvb/mantis/mantis_vp2040.c
@@ -47,8 +47,9 @@ struct tda10023_config vp2040_tda10023_cu1216_config = {
.invert = 1,
};
-static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct mantis_pci *mantis = fe->dvb->priv;
struct i2c_adapter *adapter = &mantis->adapter;
@@ -59,13 +60,13 @@ static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_fronten
#define CU1216_IF 36125000
#define TUNER_MUL 62500
- u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+ u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
buf[2] = 0xce;
- buf[3] = (params->frequency < 150000000 ? 0x01 :
- params->frequency < 445000000 ? 0x02 : 0x04);
+ buf[3] = (p->frequency < 150000000 ? 0x01 :
+ p->frequency < 445000000 ? 0x02 : 0x04);
buf[4] = 0xde;
buf[5] = 0x20;
diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c
index 056419228363..7539a5d71029 100644
--- a/drivers/media/dvb/ngene/ngene-cards.c
+++ b/drivers/media/dvb/ngene/ngene-cards.c
@@ -216,9 +216,10 @@ static int demod_attach_drxk(struct ngene_channel *chan,
struct drxk_config config;
memset(&config, 0, sizeof(config));
+ config.microcode_name = "drxk_a3.mc";
config.adr = 0x29 + (chan->number ^ 2);
- chan->fe = dvb_attach(drxk_attach, &config, i2c, &chan->fe2);
+ chan->fe = dvb_attach(drxk_attach, &config, i2c);
if (!chan->fe) {
printk(KERN_ERR "No DRXK found!\n");
return -ENODEV;
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 80fb51004461..e1f20c236989 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -445,9 +445,9 @@ static inline u32 divide(u32 numerator, u32 denominator)
}
/* LG Innotek TDTE-E001P (Infineon TUA6034) */
-static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct pluto *pluto = frontend_to_pluto(fe);
struct i2c_msg msg;
int ret;
@@ -478,7 +478,7 @@ static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe,
else
buf[3] = 0x04;
- if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+ if (p->bandwidth_hz == 8000000)
buf[3] |= 0x08;
if (sizeof(buf) == 6) {
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c
index b81df5fafe26..15b35c4725f1 100644
--- a/drivers/media/dvb/pt1/pt1.c
+++ b/drivers/media/dvb/pt1/pt1.c
@@ -28,6 +28,7 @@
#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/ratelimit.h>
#include "dvbdev.h"
#include "dvb_demux.h"
@@ -77,6 +78,8 @@ struct pt1 {
struct pt1_adapter *adaps[PT1_NR_ADAPS];
struct pt1_table *tables;
struct task_struct *kthread;
+ int table_index;
+ int buf_index;
struct mutex lock;
int power;
@@ -90,12 +93,12 @@ struct pt1_adapter {
u8 *buf;
int upacket_count;
int packet_count;
+ int st_count;
struct dvb_adapter adap;
struct dvb_demux demux;
int users;
struct dmxdev dmxdev;
- struct dvb_net net;
struct dvb_frontend *fe;
int (*orig_set_voltage)(struct dvb_frontend *fe,
fe_sec_voltage_t voltage);
@@ -119,7 +122,7 @@ static u32 pt1_read_reg(struct pt1 *pt1, int reg)
return readl(pt1->regs + reg * 4);
}
-static int pt1_nr_tables = 64;
+static int pt1_nr_tables = 8;
module_param_named(nr_tables, pt1_nr_tables, int, 0);
static void pt1_increment_table_count(struct pt1 *pt1)
@@ -264,6 +267,7 @@ static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
struct pt1_adapter *adap;
int offset;
u8 *buf;
+ int sc;
if (!page->upackets[PT1_NR_UPACKETS - 1])
return 0;
@@ -280,6 +284,16 @@ static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
else if (!adap->upacket_count)
continue;
+ if (upacket >> 24 & 1)
+ printk_ratelimited(KERN_INFO "earth-pt1: device "
+ "buffer overflowing. table[%d] buf[%d]\n",
+ pt1->table_index, pt1->buf_index);
+ sc = upacket >> 26 & 0x7;
+ if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7))
+ printk_ratelimited(KERN_INFO "earth-pt1: data loss"
+ " in streamID(adapter)[%d]\n", index);
+ adap->st_count = sc;
+
buf = adap->buf;
offset = adap->packet_count * 188 + adap->upacket_count * 3;
buf[offset] = upacket >> 16;
@@ -303,30 +317,25 @@ static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
static int pt1_thread(void *data)
{
struct pt1 *pt1;
- int table_index;
- int buf_index;
struct pt1_buffer_page *page;
pt1 = data;
set_freezable();
- table_index = 0;
- buf_index = 0;
-
while (!kthread_should_stop()) {
try_to_freeze();
- page = pt1->tables[table_index].bufs[buf_index].page;
+ page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page;
if (!pt1_filter(pt1, page)) {
schedule_timeout_interruptible((HZ + 999) / 1000);
continue;
}
- if (++buf_index >= PT1_NR_BUFS) {
+ if (++pt1->buf_index >= PT1_NR_BUFS) {
pt1_increment_table_count(pt1);
- buf_index = 0;
- if (++table_index >= pt1_nr_tables)
- table_index = 0;
+ pt1->buf_index = 0;
+ if (++pt1->table_index >= pt1_nr_tables)
+ pt1->table_index = 0;
}
}
@@ -477,21 +486,60 @@ err:
return ret;
}
+static int pt1_start_polling(struct pt1 *pt1)
+{
+ int ret = 0;
+
+ mutex_lock(&pt1->lock);
+ if (!pt1->kthread) {
+ pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1");
+ if (IS_ERR(pt1->kthread)) {
+ ret = PTR_ERR(pt1->kthread);
+ pt1->kthread = NULL;
+ }
+ }
+ mutex_unlock(&pt1->lock);
+ return ret;
+}
+
static int pt1_start_feed(struct dvb_demux_feed *feed)
{
struct pt1_adapter *adap;
adap = container_of(feed->demux, struct pt1_adapter, demux);
- if (!adap->users++)
+ if (!adap->users++) {
+ int ret;
+
+ ret = pt1_start_polling(adap->pt1);
+ if (ret)
+ return ret;
pt1_set_stream(adap->pt1, adap->index, 1);
+ }
return 0;
}
+static void pt1_stop_polling(struct pt1 *pt1)
+{
+ int i, count;
+
+ mutex_lock(&pt1->lock);
+ for (i = 0, count = 0; i < PT1_NR_ADAPS; i++)
+ count += pt1->adaps[i]->users;
+
+ if (count == 0 && pt1->kthread) {
+ kthread_stop(pt1->kthread);
+ pt1->kthread = NULL;
+ }
+ mutex_unlock(&pt1->lock);
+}
+
static int pt1_stop_feed(struct dvb_demux_feed *feed)
{
struct pt1_adapter *adap;
adap = container_of(feed->demux, struct pt1_adapter, demux);
- if (!--adap->users)
+ if (!--adap->users) {
pt1_set_stream(adap->pt1, adap->index, 0);
+ pt1_stop_polling(adap->pt1);
+ }
return 0;
}
@@ -575,7 +623,6 @@ static int pt1_wakeup(struct dvb_frontend *fe)
static void pt1_free_adapter(struct pt1_adapter *adap)
{
- dvb_net_release(&adap->net);
adap->demux.dmx.close(&adap->demux.dmx);
dvb_dmxdev_release(&adap->dmxdev);
dvb_dmx_release(&adap->demux);
@@ -616,6 +663,7 @@ pt1_alloc_adapter(struct pt1 *pt1)
adap->buf = buf;
adap->upacket_count = 0;
adap->packet_count = 0;
+ adap->st_count = -1;
dvb_adap = &adap->adap;
dvb_adap->priv = adap;
@@ -644,8 +692,6 @@ pt1_alloc_adapter(struct pt1 *pt1)
if (ret < 0)
goto err_dmx_release;
- dvb_net_init(dvb_adap, &adap->net, &demux->dmx);
-
return adap;
err_dmx_release:
@@ -1020,7 +1066,8 @@ static void __devexit pt1_remove(struct pci_dev *pdev)
pt1 = pci_get_drvdata(pdev);
regs = pt1->regs;
- kthread_stop(pt1->kthread);
+ if (pt1->kthread)
+ kthread_stop(pt1->kthread);
pt1_cleanup_tables(pt1);
pt1_cleanup_frontends(pt1);
pt1_disable_ram(pt1);
@@ -1043,7 +1090,6 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *regs;
struct pt1 *pt1;
struct i2c_adapter *i2c_adap;
- struct task_struct *kthread;
ret = pci_enable_device(pdev);
if (ret < 0)
@@ -1139,17 +1185,8 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret < 0)
goto err_pt1_cleanup_frontends;
- kthread = kthread_run(pt1_thread, pt1, "pt1");
- if (IS_ERR(kthread)) {
- ret = PTR_ERR(kthread);
- goto err_pt1_cleanup_tables;
- }
-
- pt1->kthread = kthread;
return 0;
-err_pt1_cleanup_tables:
- pt1_cleanup_tables(pt1);
err_pt1_cleanup_frontends:
pt1_cleanup_frontends(pt1);
err_pt1_disable_ram:
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.c b/drivers/media/dvb/pt1/va1j5jf8007s.c
index 451641c0c1d2..d980dfb21e5e 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007s.c
+++ b/drivers/media/dvb/pt1/va1j5jf8007s.c
@@ -385,7 +385,7 @@ va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock)
static int
va1j5jf8007s_tune(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
+ bool re_tune,
unsigned int mode_flags, unsigned int *delay,
fe_status_t *status)
{
@@ -395,7 +395,7 @@ va1j5jf8007s_tune(struct dvb_frontend *fe,
state = fe->demodulator_priv;
- if (params != NULL)
+ if (re_tune)
state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1;
switch (state->tune_state) {
@@ -579,9 +579,9 @@ static void va1j5jf8007s_release(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops va1j5jf8007s_ops = {
+ .delsys = { SYS_ISDBS },
.info = {
.name = "VA1J5JF8007/VA1J5JF8011 ISDB-S",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1000,
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.c b/drivers/media/dvb/pt1/va1j5jf8007t.c
index 0f085c3e571b..2db15159d514 100644
--- a/drivers/media/dvb/pt1/va1j5jf8007t.c
+++ b/drivers/media/dvb/pt1/va1j5jf8007t.c
@@ -264,7 +264,7 @@ static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state,
static int
va1j5jf8007t_tune(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
+ bool re_tune,
unsigned int mode_flags, unsigned int *delay,
fe_status_t *status)
{
@@ -274,7 +274,7 @@ va1j5jf8007t_tune(struct dvb_frontend *fe,
state = fe->demodulator_priv;
- if (params != NULL)
+ if (re_tune)
state->tune_state = VA1J5JF8007T_SET_FREQUENCY;
switch (state->tune_state) {
@@ -428,9 +428,9 @@ static void va1j5jf8007t_release(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops va1j5jf8007t_ops = {
+ .delsys = { SYS_ISDBT },
.info = {
.name = "VA1J5JF8007/VA1J5JF8011 ISDB-T",
- .type = FE_OFDM,
.frequency_min = 90000000,
.frequency_max = 770000000,
.frequency_stepsize = 142857,
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
index 37c594f82782..aa77e54a8fae 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -49,9 +49,6 @@ struct smsdvb_client_t {
struct completion tune_done;
- /* todo: save freq/band instead whole struct */
- struct dvb_frontend_parameters fe_params;
-
struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
int event_fe_state;
int event_unc_state;
@@ -591,8 +588,7 @@ static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
return 0;
}
-static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct smsdvb_client_t *client =
@@ -658,8 +654,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
&client->tune_done);
}
-static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct smsdvb_client_t *client =
@@ -723,8 +718,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
&client->tune_done);
}
-static int smsdvb_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int smsdvb_set_frontend(struct dvb_frontend *fe)
{
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
@@ -733,26 +727,138 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
switch (smscore_get_device_mode(coredev)) {
case DEVICE_MODE_DVBT:
case DEVICE_MODE_DVBT_BDA:
- return smsdvb_dvbt_set_frontend(fe, fep);
+ return smsdvb_dvbt_set_frontend(fe);
case DEVICE_MODE_ISDBT:
case DEVICE_MODE_ISDBT_BDA:
- return smsdvb_isdbt_set_frontend(fe, fep);
+ return smsdvb_isdbt_set_frontend(fe);
default:
return -EINVAL;
}
}
-static int smsdvb_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int smsdvb_get_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
+ struct smscore_device_t *coredev = client->coredev;
+ struct TRANSMISSION_STATISTICS_S *td =
+ &client->sms_stat_dvb.TransmissionData;
- sms_debug("");
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_DVBT:
+ case DEVICE_MODE_DVBT_BDA:
+ fep->frequency = td->Frequency;
- /* todo: */
- memcpy(fep, &client->fe_params,
- sizeof(struct dvb_frontend_parameters));
+ switch (td->Bandwidth) {
+ case 6:
+ fep->bandwidth_hz = 6000000;
+ break;
+ case 7:
+ fep->bandwidth_hz = 7000000;
+ break;
+ case 8:
+ fep->bandwidth_hz = 8000000;
+ break;
+ }
+
+ switch (td->TransmissionMode) {
+ case 2:
+ fep->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 8:
+ fep->transmission_mode = TRANSMISSION_MODE_8K;
+ }
+
+ switch (td->GuardInterval) {
+ case 0:
+ fep->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ fep->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ fep->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ fep->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ }
+
+ switch (td->CodeRate) {
+ case 0:
+ fep->code_rate_HP = FEC_1_2;
+ break;
+ case 1:
+ fep->code_rate_HP = FEC_2_3;
+ break;
+ case 2:
+ fep->code_rate_HP = FEC_3_4;
+ break;
+ case 3:
+ fep->code_rate_HP = FEC_5_6;
+ break;
+ case 4:
+ fep->code_rate_HP = FEC_7_8;
+ break;
+ }
+
+ switch (td->LPCodeRate) {
+ case 0:
+ fep->code_rate_LP = FEC_1_2;
+ break;
+ case 1:
+ fep->code_rate_LP = FEC_2_3;
+ break;
+ case 2:
+ fep->code_rate_LP = FEC_3_4;
+ break;
+ case 3:
+ fep->code_rate_LP = FEC_5_6;
+ break;
+ case 4:
+ fep->code_rate_LP = FEC_7_8;
+ break;
+ }
+
+ switch (td->Constellation) {
+ case 0:
+ fep->modulation = QPSK;
+ break;
+ case 1:
+ fep->modulation = QAM_16;
+ break;
+ case 2:
+ fep->modulation = QAM_64;
+ break;
+ }
+
+ switch (td->Hierarchy) {
+ case 0:
+ fep->hierarchy = HIERARCHY_NONE;
+ break;
+ case 1:
+ fep->hierarchy = HIERARCHY_1;
+ break;
+ case 2:
+ fep->hierarchy = HIERARCHY_2;
+ break;
+ case 3:
+ fep->hierarchy = HIERARCHY_4;
+ break;
+ }
+
+ fep->inversion = INVERSION_AUTO;
+ break;
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ fep->frequency = td->Frequency;
+ fep->bandwidth_hz = 6000000;
+ /* todo: retrive the other parameters */
+ break;
+ default:
+ return -EINVAL;
+ }
return 0;
}
@@ -789,7 +895,6 @@ static void smsdvb_release(struct dvb_frontend *fe)
static struct dvb_frontend_ops smsdvb_fe_ops = {
.info = {
.name = "Siano Mobile Digital MDTV Receiver",
- .type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 250000,
@@ -873,6 +978,17 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
memcpy(&client->frontend.ops, &smsdvb_fe_ops,
sizeof(struct dvb_frontend_ops));
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_DVBT:
+ case DEVICE_MODE_DVBT_BDA:
+ client->frontend.ops.delsys[0] = SYS_DVBT;
+ break;
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ client->frontend.ops.delsys[0] = SYS_ISDBT;
+ break;
+ }
+
rc = dvb_register_frontend(&client->adapter, &client->frontend);
if (rc < 0) {
sms_err("frontend registration failed %d", rc);
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 3d20719fce1a..4bd8bd56befc 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -53,7 +53,6 @@
#include <asm/unaligned.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <linux/dvb/frontend.h>
@@ -991,7 +990,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
if (feed->type == DMX_TYPE_TS) {
if ((feed->ts_type & TS_DECODER) &&
- (feed->pes_type < DMX_TS_PES_OTHER)) {
+ (feed->pes_type <= DMX_TS_PES_PCR)) {
switch (demux->dmx.frontend->source) {
case DMX_MEMORY_FE:
if (feed->ts_type & TS_DECODER)
@@ -1568,20 +1567,27 @@ static int get_firmware(struct av7110* av7110)
return ret;
}
-static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct av7110* av7110 = fe->dvb->priv;
u8 pwr = 0;
u8 buf[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- u32 div = (params->frequency + 479500) / 125;
+ u32 div = (p->frequency + 479500) / 125;
- if (params->frequency > 2000000) pwr = 3;
- else if (params->frequency > 1800000) pwr = 2;
- else if (params->frequency > 1600000) pwr = 1;
- else if (params->frequency > 1200000) pwr = 0;
- else if (params->frequency >= 1100000) pwr = 1;
- else pwr = 2;
+ if (p->frequency > 2000000)
+ pwr = 3;
+ else if (p->frequency > 1800000)
+ pwr = 2;
+ else if (p->frequency > 1600000)
+ pwr = 1;
+ else if (p->frequency > 1200000)
+ pwr = 0;
+ else if (p->frequency >= 1100000)
+ pwr = 1;
+ else
+ pwr = 2;
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
@@ -1604,19 +1610,20 @@ static struct ves1x93_config alps_bsrv2_config = {
.invert_pwm = 0,
};
-static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct av7110* av7110 = fe->dvb->priv;
u32 div;
u8 data[4];
struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
- div = (params->frequency + 35937500 + 31250) / 62500;
+ div = (p->frequency + 35937500 + 31250) / 62500;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = 0x85 | ((div >> 10) & 0x60);
- data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -1635,14 +1642,15 @@ static struct ves1820_config alps_tdbe2_config = {
-static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct av7110* av7110 = fe->dvb->priv;
u32 div;
u8 data[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
- div = params->frequency / 125;
+ div = p->frequency / 125;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = 0x8e;
@@ -1661,11 +1669,12 @@ static struct tda8083_config grundig_29504_451_config = {
-static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int philips_cd1516_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct av7110* av7110 = fe->dvb->priv;
u32 div;
- u32 f = params->frequency;
+ u32 f = p->frequency;
u8 data[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
@@ -1692,16 +1701,17 @@ static struct ves1820_config philips_cd1516_config = {
-static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct av7110* av7110 = fe->dvb->priv;
u32 div, pwr;
u8 data[4];
struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
- div = (params->frequency + 36200000) / 166666;
+ div = (p->frequency + 36200000) / 166666;
- if (params->frequency <= 782000000)
+ if (p->frequency <= 782000000)
pwr = 1;
else
pwr = 2;
@@ -1829,8 +1839,9 @@ static u8 nexusca_stv0297_inittab[] = {
0xff, 0xff,
};
-static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct av7110* av7110 = fe->dvb->priv;
u32 div;
u8 data[4];
@@ -1838,19 +1849,19 @@ static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_
struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 };
int i;
- div = (params->frequency + 36150000 + 31250) / 62500;
+ div = (p->frequency + 36150000 + 31250) / 62500;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = 0xce;
- if (params->frequency < 45000000)
+ if (p->frequency < 45000000)
return -EINVAL;
- else if (params->frequency < 137000000)
+ else if (p->frequency < 137000000)
data[3] = 0x01;
- else if (params->frequency < 403000000)
+ else if (p->frequency < 403000000)
data[3] = 0x02;
- else if (params->frequency < 860000000)
+ else if (p->frequency < 860000000)
data[3] = 0x04;
else
return -EINVAL;
@@ -1884,27 +1895,36 @@ static struct stv0297_config nexusca_stv0297_config = {
-static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct av7110* av7110 = fe->dvb->priv;
u32 div;
u8 cfg, cpump, band_select;
u8 data[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
- div = (36125000 + params->frequency) / 166666;
+ div = (36125000 + p->frequency) / 166666;
cfg = 0x88;
- if (params->frequency < 175000000) cpump = 2;
- else if (params->frequency < 390000000) cpump = 1;
- else if (params->frequency < 470000000) cpump = 2;
- else if (params->frequency < 750000000) cpump = 1;
- else cpump = 3;
+ if (p->frequency < 175000000)
+ cpump = 2;
+ else if (p->frequency < 390000000)
+ cpump = 1;
+ else if (p->frequency < 470000000)
+ cpump = 2;
+ else if (p->frequency < 750000000)
+ cpump = 1;
+ else
+ cpump = 3;
- if (params->frequency < 175000000) band_select = 0x0e;
- else if (params->frequency < 470000000) band_select = 0x05;
- else band_select = 0x03;
+ if (p->frequency < 175000000)
+ band_select = 0x0e;
+ else if (p->frequency < 470000000)
+ band_select = 0x05;
+ else
+ band_select = 0x03;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
@@ -1964,15 +1984,14 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
return ret;
}
-static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int av7110_fe_set_frontend(struct dvb_frontend *fe)
{
struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
- if (!ret) {
- av7110->saved_fe_params = *params;
- ret = av7110->fe_set_frontend(fe, params);
- }
+ if (!ret)
+ ret = av7110->fe_set_frontend(fe);
+
return ret;
}
@@ -2081,7 +2100,7 @@ static void dvb_s_recover(struct av7110* av7110)
msleep(20);
av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
- av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params);
+ av7110_fe_set_frontend(av7110->fe);
}
static u8 read_pwm(struct av7110* av7110)
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index d85b8512ac30..88b3b2d6cc0e 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -272,7 +272,6 @@ struct av7110 {
/* crash recovery */
void (*recover)(struct av7110* av7110);
- struct dvb_frontend_parameters saved_fe_params;
fe_sec_voltage_t saved_voltage;
fe_sec_tone_mode_t saved_tone;
struct dvb_diseqc_master_cmd saved_master_cmd;
@@ -286,7 +285,7 @@ struct av7110 {
int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
- int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+ int (*fe_set_frontend)(struct dvb_frontend *fe);
};
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 78d32f7e49fc..8b32e282bf5d 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -502,33 +502,33 @@ static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 sra
return 0;
}
-static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u32 div;
u8 buf[4];
struct budget *budget = (struct budget *) fe->dvb->priv;
struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
- if ((params->frequency < 950000) || (params->frequency > 2150000))
+ if ((c->frequency < 950000) || (c->frequency > 2150000))
return -EINVAL;
- div = (params->frequency + (125 - 1)) / 125; // round correctly
+ div = (c->frequency + (125 - 1)) / 125; /* round correctly */
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
buf[3] = 0x20;
- if (params->u.qpsk.symbol_rate < 4000000)
+ if (c->symbol_rate < 4000000)
buf[3] |= 1;
- if (params->frequency < 1250000)
+ if (c->frequency < 1250000)
buf[3] |= 0;
- else if (params->frequency < 1550000)
+ else if (c->frequency < 1550000)
buf[3] |= 0x40;
- else if (params->frequency < 2050000)
+ else if (c->frequency < 2050000)
buf[3] |= 0x80;
- else if (params->frequency < 2150000)
+ else if (c->frequency < 2150000)
buf[3] |= 0xC0;
if (fe->ops.i2c_gate_ctrl)
@@ -617,8 +617,9 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = {
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
};
-static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct budget *budget = (struct budget *) fe->dvb->priv;
u8 buf[6];
struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
@@ -627,13 +628,13 @@ static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
#define CU1216_IF 36125000
#define TUNER_MUL 62500
- u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+ u32 div = (c->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
buf[2] = 0xce;
- buf[3] = (params->frequency < 150000000 ? 0x01 :
- params->frequency < 445000000 ? 0x02 : 0x04);
+ buf[3] = (c->frequency < 150000000 ? 0x01 :
+ c->frequency < 445000000 ? 0x02 : 0x04);
buf[4] = 0xde;
buf[5] = 0x20;
@@ -697,8 +698,9 @@ static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
return 0;
}
-static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct budget *budget = (struct budget *) fe->dvb->priv;
u8 tuner_buf[4];
struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
@@ -707,7 +709,7 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
u8 band, cp, filter;
// determine charge pump
- tuner_frequency = params->frequency + 36166000;
+ tuner_frequency = c->frequency + 36166000;
if (tuner_frequency < 87000000)
return -EINVAL;
else if (tuner_frequency < 130000000)
@@ -732,28 +734,28 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
return -EINVAL;
// determine band
- if (params->frequency < 49000000)
+ if (c->frequency < 49000000)
return -EINVAL;
- else if (params->frequency < 161000000)
+ else if (c->frequency < 161000000)
band = 1;
- else if (params->frequency < 444000000)
+ else if (c->frequency < 444000000)
band = 2;
- else if (params->frequency < 861000000)
+ else if (c->frequency < 861000000)
band = 4;
else
return -EINVAL;
// setup PLL filter
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (c->bandwidth_hz) {
+ case 6000000:
filter = 0;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
filter = 0;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
filter = 1;
break;
@@ -763,7 +765,7 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
// calculate divisor
// ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
- tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000;
+ tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000;
// setup tuner buffer
tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index ca02e9722172..98e524178765 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -193,7 +193,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
dev->input_phys = budget_ci->ir.phys;
dev->input_id.bustype = BUS_PCI;
dev->input_id.version = 1;
- dev->scanmask = 0xff;
if (saa->pci->subsystem_vendor) {
dev->input_id.vendor = saa->pci->subsystem_vendor;
dev->input_id.product = saa->pci->subsystem_device;
@@ -234,6 +233,8 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
dev->map_name = RC_MAP_BUDGET_CI_OLD;
break;
}
+ if (!budget_ci->ir.full_rc5)
+ dev->scanmask = 0xff;
error = rc_register_device(dev);
if (error) {
@@ -659,33 +660,33 @@ static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
return 0;
}
-static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u32 div;
u8 buf[4];
struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
- if ((params->frequency < 950000) || (params->frequency > 2150000))
+ if ((p->frequency < 950000) || (p->frequency > 2150000))
return -EINVAL;
- div = (params->frequency + (500 - 1)) / 500; // round correctly
+ div = (p->frequency + (500 - 1)) / 500; /* round correctly */
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
buf[3] = 0x20;
- if (params->u.qpsk.symbol_rate < 4000000)
+ if (p->symbol_rate < 4000000)
buf[3] |= 1;
- if (params->frequency < 1250000)
+ if (p->frequency < 1250000)
buf[3] |= 0;
- else if (params->frequency < 1550000)
+ else if (p->frequency < 1550000)
buf[3] |= 0x40;
- else if (params->frequency < 2050000)
+ else if (p->frequency < 2050000)
buf[3] |= 0x80;
- else if (params->frequency < 2150000)
+ else if (p->frequency < 2150000)
buf[3] |= 0xC0;
if (fe->ops.i2c_gate_ctrl)
@@ -740,8 +741,9 @@ static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
return 0;
}
-static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u8 tuner_buf[4];
struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
@@ -749,7 +751,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb
u8 band, cp, filter;
// determine charge pump
- tuner_frequency = params->frequency + 36130000;
+ tuner_frequency = p->frequency + 36130000;
if (tuner_frequency < 87000000)
return -EINVAL;
else if (tuner_frequency < 130000000)
@@ -774,30 +776,30 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb
return -EINVAL;
// determine band
- if (params->frequency < 49000000)
+ if (p->frequency < 49000000)
return -EINVAL;
- else if (params->frequency < 159000000)
+ else if (p->frequency < 159000000)
band = 1;
- else if (params->frequency < 444000000)
+ else if (p->frequency < 444000000)
band = 2;
- else if (params->frequency < 861000000)
+ else if (p->frequency < 861000000)
band = 4;
else
return -EINVAL;
// setup PLL filter and TDA9889
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (p->bandwidth_hz) {
+ case 6000000:
tda1004x_writereg(fe, 0x0C, 0x14);
filter = 0;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
tda1004x_writereg(fe, 0x0C, 0x80);
filter = 0;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
tda1004x_writereg(fe, 0x0C, 0x14);
filter = 1;
break;
@@ -808,7 +810,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb
// calculate divisor
// ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
- tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+ tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000;
// setup tuner buffer
tuner_buf[0] = tuner_frequency >> 8;
@@ -855,8 +857,9 @@ static struct tda1004x_config philips_tdm1316l_config_invert = {
.request_firmware = philips_tdm1316l_request_firmware,
};
-static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u8 tuner_buf[5];
struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
@@ -867,7 +870,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc
u8 band, cp, filter;
// determine charge pump
- tuner_frequency = params->frequency + 36125000;
+ tuner_frequency = p->frequency + 36125000;
if (tuner_frequency < 87000000)
return -EINVAL;
else if (tuner_frequency < 130000000) {
@@ -904,7 +907,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc
filter = 1;
// calculate divisor
- tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
+ tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500;
// setup tuner buffer
tuner_buf[0] = tuner_frequency >> 8;
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 3395d1a90516..2cb35c23d2ac 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -261,19 +261,25 @@ static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_c
return 0;
}
-static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
u8 pwr = 0;
u8 buf[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- u32 div = (params->frequency + 479500) / 125;
-
- if (params->frequency > 2000000) pwr = 3;
- else if (params->frequency > 1800000) pwr = 2;
- else if (params->frequency > 1600000) pwr = 1;
- else if (params->frequency > 1200000) pwr = 0;
- else if (params->frequency >= 1100000) pwr = 1;
+ u32 div = (p->frequency + 479500) / 125;
+
+ if (p->frequency > 2000000)
+ pwr = 3;
+ else if (p->frequency > 1800000)
+ pwr = 2;
+ else if (p->frequency > 1600000)
+ pwr = 1;
+ else if (p->frequency > 1200000)
+ pwr = 0;
+ else if (p->frequency >= 1100000)
+ pwr = 1;
else pwr = 2;
buf[0] = (div >> 8) & 0x7f;
@@ -297,14 +303,15 @@ static struct ves1x93_config alps_bsrv2_config = {
.invert_pwm = 0,
};
-static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
u32 div;
u8 data[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
- div = params->frequency / 125;
+ div = p->frequency / 125;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = 0x8e;
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index d238fb9371a7..b21bcce66708 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -200,19 +200,25 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m
return 0;
}
-static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct budget* budget = (struct budget*) fe->dvb->priv;
u8 pwr = 0;
u8 buf[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- u32 div = (params->frequency + 479500) / 125;
-
- if (params->frequency > 2000000) pwr = 3;
- else if (params->frequency > 1800000) pwr = 2;
- else if (params->frequency > 1600000) pwr = 1;
- else if (params->frequency > 1200000) pwr = 0;
- else if (params->frequency >= 1100000) pwr = 1;
+ u32 div = (c->frequency + 479500) / 125;
+
+ if (c->frequency > 2000000)
+ pwr = 3;
+ else if (c->frequency > 1800000)
+ pwr = 2;
+ else if (c->frequency > 1600000)
+ pwr = 1;
+ else if (c->frequency > 1200000)
+ pwr = 0;
+ else if (c->frequency >= 1100000)
+ pwr = 1;
else pwr = 2;
buf[0] = (div >> 8) & 0x7f;
@@ -236,19 +242,20 @@ static struct ves1x93_config alps_bsrv2_config =
.invert_pwm = 0,
};
-static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
u8 data[4];
struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
- div = (params->frequency + 35937500 + 31250) / 62500;
+ div = (c->frequency + 35937500 + 31250) / 62500;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = 0x85 | ((div >> 10) & 0x60);
- data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -263,8 +270,9 @@ static struct ves1820_config alps_tdbe2_config = {
.selagc = VES1820_SELAGC_SIGNAMPERR,
};
-static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct budget *budget = fe->dvb->priv;
u8 *tuner_addr = fe->tuner_priv;
u32 div;
@@ -277,19 +285,27 @@ static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dv
else
msg.addr = 0x61;
- div = (36125000 + params->frequency) / 166666;
+ div = (36125000 + c->frequency) / 166666;
cfg = 0x88;
- if (params->frequency < 175000000) cpump = 2;
- else if (params->frequency < 390000000) cpump = 1;
- else if (params->frequency < 470000000) cpump = 2;
- else if (params->frequency < 750000000) cpump = 1;
- else cpump = 3;
+ if (c->frequency < 175000000)
+ cpump = 2;
+ else if (c->frequency < 390000000)
+ cpump = 1;
+ else if (c->frequency < 470000000)
+ cpump = 2;
+ else if (c->frequency < 750000000)
+ cpump = 1;
+ else
+ cpump = 3;
- if (params->frequency < 175000000) band_select = 0x0e;
- else if (params->frequency < 470000000) band_select = 0x05;
- else band_select = 0x03;
+ if (c->frequency < 175000000)
+ band_select = 0x0e;
+ else if (c->frequency < 470000000)
+ band_select = 0x05;
+ else
+ band_select = 0x03;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
@@ -312,14 +328,15 @@ static struct l64781_config grundig_29504_401_config_activy = {
static u8 tuner_address_grundig_29504_401_activy = 0x60;
-static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
u8 data[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
- div = params->frequency / 125;
+ div = c->frequency / 125;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = 0x8e;
@@ -335,14 +352,15 @@ static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
};
-static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int s5h1420_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
u8 data[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
- div = params->frequency / 1000;
+ div = c->frequency / 1000;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = 0xc2;
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index e90192fdde11..5b682cc4c814 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1017,19 +1017,20 @@ static u32 functionality(struct i2c_adapter *adapter)
-static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdmb7_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 data[4];
struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) };
u32 div;
- div = (params->frequency + 36166667) / 166667;
+ div = (p->frequency + 36166667) / 166667;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = ((div >> 10) & 0x60) | 0x85;
- data[3] = params->frequency < 592000000 ? 0x40 : 0x80;
+ data[3] = p->frequency < 592000000 ? 0x40 : 0x80;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -1071,8 +1072,9 @@ static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe)
return 0;
}
-static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 tuner_buf[4];
struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
@@ -1080,7 +1082,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb
u8 band, cp, filter;
// determine charge pump
- tuner_frequency = params->frequency + 36130000;
+ tuner_frequency = p->frequency + 36130000;
if (tuner_frequency < 87000000) return -EINVAL;
else if (tuner_frequency < 130000000) cp = 3;
else if (tuner_frequency < 160000000) cp = 5;
@@ -1094,25 +1096,29 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb
else return -EINVAL;
// determine band
- if (params->frequency < 49000000) return -EINVAL;
- else if (params->frequency < 159000000) band = 1;
- else if (params->frequency < 444000000) band = 2;
- else if (params->frequency < 861000000) band = 4;
+ if (p->frequency < 49000000)
+ return -EINVAL;
+ else if (p->frequency < 159000000)
+ band = 1;
+ else if (p->frequency < 444000000)
+ band = 2;
+ else if (p->frequency < 861000000)
+ band = 4;
else return -EINVAL;
// setup PLL filter
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (p->bandwidth_hz) {
+ case 6000000:
tda1004x_writereg(fe, 0x0C, 0);
filter = 0;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
tda1004x_writereg(fe, 0x0C, 0);
filter = 0;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
tda1004x_writereg(fe, 0x0C, 0xFF);
filter = 1;
break;
@@ -1123,7 +1129,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb
// calculate divisor
// ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
- tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+ tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000;
// setup tuner buffer
tuner_buf[0] = tuner_frequency >> 8;
@@ -1273,23 +1279,24 @@ static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32
return 0;
}
-static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 buf[4];
u32 div;
struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
- if ((params->frequency < 950000) || (params->frequency > 2150000))
+ if ((p->frequency < 950000) || (p->frequency > 2150000))
return -EINVAL;
- div = (params->frequency + (125 - 1)) / 125; // round correctly
+ div = (p->frequency + (125 - 1)) / 125; /* round correctly */
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
buf[3] = 0xC4;
- if (params->frequency > 1530000)
+ if (p->frequency > 1530000)
buf[3] = 0xC0;
/* BSBE1 wants XCE bit set */
@@ -1316,14 +1323,15 @@ static struct stv0299_config alps_stv0299_config = {
.set_symbol_rate = alps_stv0299_set_symbol_rate,
};
-static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 buf[4];
u32 div;
struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
- div = params->frequency / 125;
+ div = p->frequency / 125;
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
@@ -1343,19 +1351,20 @@ static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
.demod_address = 0x68,
};
-static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ttusb* ttusb = fe->dvb->priv;
u32 div;
u8 data[4];
struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
- div = (params->frequency + 35937500 + 31250) / 62500;
+ div = (p->frequency + 35937500 + 31250) / 62500;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = 0x85 | ((div >> 10) & 0x60);
- data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -1387,8 +1396,9 @@ static u8 read_pwm(struct ttusb* ttusb)
}
-static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv;
u8 tuner_buf[5];
struct i2c_msg tuner_msg = {.addr = 0x60,
@@ -1399,7 +1409,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc
u8 band, cp, filter;
// determine charge pump
- tuner_frequency = params->frequency;
+ tuner_frequency = p->frequency;
if (tuner_frequency < 87000000) {return -EINVAL;}
else if (tuner_frequency < 130000000) {cp = 3; band = 1;}
else if (tuner_frequency < 160000000) {cp = 5; band = 1;}
@@ -1417,7 +1427,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc
// calculate divisor
// (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz
- tuner_frequency = ((params->frequency + 36125000) / 62500);
+ tuner_frequency = ((p->frequency + 36125000) / 62500);
// setup tuner buffer
tuner_buf[0] = tuner_frequency >> 8;
@@ -1694,10 +1704,8 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
ttusb->i2c_adap.dev.parent = &udev->dev;
result = i2c_add_adapter(&ttusb->i2c_adap);
- if (result) {
- dvb_unregister_adapter (&ttusb->adapter);
- return result;
- }
+ if (result)
+ goto err_unregister_adapter;
memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux));
@@ -1714,33 +1722,29 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
ttusb->dvb_demux.stop_feed = ttusb_stop_feed;
ttusb->dvb_demux.write_to_decoder = NULL;
- if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) {
+ result = dvb_dmx_init(&ttusb->dvb_demux);
+ if (result < 0) {
printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result);
- i2c_del_adapter(&ttusb->i2c_adap);
- dvb_unregister_adapter (&ttusb->adapter);
- return -ENODEV;
+ result = -ENODEV;
+ goto err_i2c_del_adapter;
}
//FIXME dmxdev (nur WAS?)
ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum;
ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx;
ttusb->dmxdev.capabilities = 0;
- if ((result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter)) < 0) {
+ result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter);
+ if (result < 0) {
printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n",
result);
- dvb_dmx_release(&ttusb->dvb_demux);
- i2c_del_adapter(&ttusb->i2c_adap);
- dvb_unregister_adapter (&ttusb->adapter);
- return -ENODEV;
+ result = -ENODEV;
+ goto err_release_dmx;
}
if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) {
printk("ttusb_dvb: dvb_net_init failed!\n");
- dvb_dmxdev_release(&ttusb->dmxdev);
- dvb_dmx_release(&ttusb->dvb_demux);
- i2c_del_adapter(&ttusb->i2c_adap);
- dvb_unregister_adapter (&ttusb->adapter);
- return -ENODEV;
+ result = -ENODEV;
+ goto err_release_dmxdev;
}
usb_set_intfdata(intf, (void *) ttusb);
@@ -1748,6 +1752,16 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
frontend_init(ttusb);
return 0;
+
+err_release_dmxdev:
+ dvb_dmxdev_release(&ttusb->dmxdev);
+err_release_dmx:
+ dvb_dmx_release(&ttusb->dvb_demux);
+err_i2c_del_adapter:
+ i2c_del_adapter(&ttusb->i2c_adap);
+err_unregister_adapter:
+ dvb_unregister_adapter (&ttusb->adapter);
+ return result;
}
static void ttusb_disconnect(struct usb_interface *intf)
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index 21260aad1e54..5c45c9d0712d 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -87,8 +87,9 @@ static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe,
return 0;
}
-static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
u8 b[] = { 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x00,
@@ -113,8 +114,9 @@ static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe,
return 0;
}
-static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
u8 b[] = { 0x00, 0x00, 0x00, 0x01,
@@ -135,7 +137,7 @@ static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_fron
freq = htonl(p->frequency +
(state->hi_band ? LOF_HI : LOF_LO));
memcpy(&b[4], &freq, sizeof(u32));
- sym_rate = htonl(p->u.qam.symbol_rate);
+ sym_rate = htonl(p->symbol_rate);
memcpy(&b[12], &sym_rate, sizeof(u32));
band = htonl(state->hi_band ? LOF_HI : LOF_LO);
memcpy(&b[24], &band, sizeof(u32));
@@ -241,10 +243,9 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
}
static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
-
+ .delsys = { SYS_DVBT },
.info = {
.name = "TechnoTrend/Hauppauge DEC2000-t Frontend",
- .type = FE_OFDM,
.frequency_min = 51000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
@@ -265,10 +266,9 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
};
static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
-
+ .delsys = { SYS_DVBS },
.info = {
.name = "TechnoTrend/Hauppauge DEC3000-s Frontend",
- .type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 125,
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 6edc9ba81203..6f9eb94e85b3 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -108,8 +108,7 @@ static long media_device_enum_entities(struct media_device *mdev,
u_ent.group_id = ent->group_id;
u_ent.pads = ent->num_pads;
u_ent.links = ent->num_links - ent->num_backlinks;
- u_ent.v4l.major = ent->v4l.major;
- u_ent.v4l.minor = ent->v4l.minor;
+ memcpy(&u_ent.raw, &ent->info, sizeof(ent->info));
if (copy_to_user(uent, &u_ent, sizeof(u_ent)))
return -EFAULT;
return 0;
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index 7b42ace419d9..f6b52d549430 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -40,7 +40,6 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#include <media/media-devnode.h>
@@ -312,7 +311,7 @@ static void __exit media_devnode_exit(void)
unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
}
-module_init(media_devnode_init)
+subsys_initcall(media_devnode_init);
module_exit(media_devnode_exit)
MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index ccd5f0d8a012..8db2d7f4b52a 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -11,20 +11,182 @@ menuconfig RADIO_ADAPTERS
if RADIO_ADAPTERS && VIDEO_V4L2
-config RADIO_CADET
- tristate "ADS Cadet AM/FM Tuner"
- depends on ISA && VIDEO_V4L2
+config RADIO_SI470X
+ bool "Silicon Labs Si470x FM Radio Receiver support"
+ depends on VIDEO_V4L2
+
+source "drivers/media/radio/si470x/Kconfig"
+
+config USB_MR800
+ tristate "AverMedia MR 800 USB FM radio support"
+ depends on USB && VIDEO_V4L2
---help---
- Choose Y here if you have one of these AM/FM radio cards, and then
- fill in the port address below.
+ Say Y here if you want to connect this type of radio to your
+ computer's USB port. Note that the audio is not digital, and
+ you must connect the line out connector to a sound card or a
+ set of speakers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-mr800.
+
+config USB_DSBR
+ tristate "D-Link/GemTek USB FM radio support"
+ depends on USB && VIDEO_V4L2
+ ---help---
+ Say Y here if you want to connect this type of radio to your
+ computer's USB port. Note that the audio is not digital, and
+ you must connect the line out connector to a sound card or a
+ set of speakers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called dsbr100.
+
+config RADIO_MAXIRADIO
+ tristate "Guillemot MAXI Radio FM 2000 radio"
+ depends on VIDEO_V4L2 && PCI && SND
+ ---help---
+ Choose Y here if you have this radio card. This card may also be
+ found as Gemtek PCI FM.
In order to control your radio card, you will need to use programs
that are compatible with the Video For Linux API. Information on
this API and pointers to "v4l" programs may be found at
<file:Documentation/video4linux/API.html>.
- Further documentation on this driver can be found on the WWW at
- <http://linux.blackhawke.net/cadet/>.
+ To compile this driver as a module, choose M here: the
+ module will be called radio-maxiradio.
+
+
+config I2C_SI4713
+ tristate "I2C driver for Silicon Labs Si4713 device"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ Say Y here if you want support to Si4713 I2C device.
+ This device driver supports only i2c bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called si4713.
+
+config RADIO_SI4713
+ tristate "Silicon Labs Si4713 FM Radio Transmitter support"
+ depends on I2C && VIDEO_V4L2
+ select I2C_SI4713
+ ---help---
+ Say Y here if you want support to Si4713 FM Radio Transmitter.
+ This device can transmit audio through FM. It can transmit
+ RDS and RBDS signals as well. This module is the v4l2 radio
+ interface for the i2c driver of this device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-si4713.
+
+config USB_KEENE
+ tristate "Keene FM Transmitter USB support"
+ depends on USB && VIDEO_V4L2
+ ---help---
+ Say Y here if you want to connect this type of FM transmitter
+ to your computer's USB port.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-keene.
+
+config RADIO_TEA5764
+ tristate "TEA5764 I2C FM radio support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ Say Y here if you want to use the TEA5764 FM chip found in
+ EZX phones. This FM chip is present in EZX phones from Motorola,
+ connected to internal pxa I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-tea5764.
+
+config RADIO_TEA5764_XTAL
+ bool "TEA5764 crystal reference"
+ depends on RADIO_TEA5764=y
+ default y
+ help
+ Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N
+ here if TEA5764 reference frequency is connected in FREQIN.
+
+config RADIO_SAA7706H
+ tristate "SAA7706H Car Radio DSP"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ Say Y here if you want to use the SAA7706H Car radio Digital
+ Signal Processor, found for instance on the Russellville development
+ board. On the russellville the device is connected to internal
+ timberdale I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called SAA7706H.
+
+config RADIO_TEF6862
+ tristate "TEF6862 Car Radio Enhanced Selectivity Tuner"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ Say Y here if you want to use the TEF6862 Car Radio Enhanced
+ Selectivity Tuner, found for instance on the Russellville development
+ board. On the russellville the device is connected to internal
+ timberdale I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called TEF6862.
+
+config RADIO_TIMBERDALE
+ tristate "Enable the Timberdale radio driver"
+ depends on MFD_TIMBERDALE && VIDEO_V4L2
+ depends on I2C # for RADIO_SAA7706H
+ select RADIO_TEF6862
+ select RADIO_SAA7706H
+ ---help---
+ This is a kind of umbrella driver for the Radio Tuner and DSP
+ found behind the Timberdale FPGA on the Russellville board.
+ Enabling this driver will automatically select the DSP and tuner.
+
+config RADIO_WL1273
+ tristate "Texas Instruments WL1273 I2C FM Radio"
+ depends on I2C && VIDEO_V4L2
+ select MFD_CORE
+ select MFD_WL1273_CORE
+ select FW_LOADER
+ ---help---
+ Choose Y here if you have this FM radio chip.
+
+ In order to control your radio card, you will need to use programs
+ that are compatible with the Video For Linux 2 API. Information on
+ this API and pointers to "v4l2" programs may be found at
+ <file:Documentation/video4linux/API.html>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-wl1273.
+
+# TI's ST based wl128x FM radio
+source "drivers/media/radio/wl128x/Kconfig"
+
+#
+# ISA drivers configuration
+#
+
+menuconfig V4L_RADIO_ISA_DRIVERS
+ bool "ISA radio devices"
+ depends on ISA
+ default n
+ ---help---
+ Say Y here to enable support for these ISA drivers.
+
+if V4L_RADIO_ISA_DRIVERS
+
+config RADIO_ISA
+ depends on ISA
+ tristate
+
+config RADIO_CADET
+ tristate "ADS Cadet AM/FM Tuner"
+ depends on ISA && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have one of these AM/FM radio cards, and then
+ fill in the port address below.
To compile this driver as a module, choose M here: the
module will be called radio-cadet.
@@ -32,6 +194,7 @@ config RADIO_CADET
config RADIO_RTRACK
tristate "AIMSlab RadioTrack (aka RadioReveal) support"
depends on ISA && VIDEO_V4L2
+ select RADIO_ISA
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address below.
@@ -45,11 +208,7 @@ config RADIO_RTRACK
You must also pass the module a suitable io parameter, 0x248 has
been reported to be used by these cards.
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>. More information is
- contained in the file
+ More information is contained in the file
<file:Documentation/video4linux/radiotrack.txt>.
To compile this driver as a module, choose M here: the
@@ -58,7 +217,7 @@ config RADIO_RTRACK
config RADIO_RTRACK_PORT
hex "RadioTrack i/o port (0x20f or 0x30f)"
depends on RADIO_RTRACK=y
- default "20f"
+ default "30f"
help
Enter either 0x30f or 0x20f here. The card default is 0x30f, if you
haven't changed the jumper setting on the card.
@@ -66,14 +225,14 @@ config RADIO_RTRACK_PORT
config RADIO_RTRACK2
tristate "AIMSlab RadioTrack II support"
depends on ISA && VIDEO_V4L2
+ select RADIO_ISA
---help---
Choose Y here if you have this FM radio card, and then fill in the
port address below.
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
+ Note: this driver hasn't been tested since a long time due to lack
+ of hardware. If you have this hardware, then please contact the
+ linux-media mailinglist.
To compile this driver as a module, choose M here: the
module will be called radio-rtrack2.
@@ -89,15 +248,11 @@ config RADIO_RTRACK2_PORT
config RADIO_AZTECH
tristate "Aztech/Packard Bell Radio"
depends on ISA && VIDEO_V4L2
+ select RADIO_ISA
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address below.
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
-
To compile this driver as a module, choose M here: the
module will be called radio-aztech.
@@ -113,6 +268,7 @@ config RADIO_AZTECH_PORT
config RADIO_GEMTEK
tristate "GemTek Radio card (or compatible) support"
depends on ISA && VIDEO_V4L2
+ select RADIO_ISA
---help---
Choose Y here if you have this FM radio card, and then fill in the
I/O port address and settings below. The following cards either have
@@ -122,23 +278,21 @@ config RADIO_GEMTEK
- Typhoon Radio card (some models)
- Hama Radio card
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
-
To compile this driver as a module, choose M here: the
module will be called radio-gemtek.
config RADIO_GEMTEK_PORT
- hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)"
+ hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c)"
depends on RADIO_GEMTEK=y
default "34c"
help
- Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
- 0x34c, if you haven't changed the jumper setting on the card. On
- Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
+ Enter either 0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c here. The
+ card default is 0x34c, if you haven't changed the jumper setting
+ on the card.
+
+ On Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
port is 0x20c, 0x248 or 0x28c.
+
If automatic I/O port probing is enabled this port will be used only
in case of automatic probing failure, ie. as a fallback.
@@ -151,21 +305,6 @@ config RADIO_GEMTEK_PROBE
following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and
0x28c.
-config RADIO_MAXIRADIO
- tristate "Guillemot MAXI Radio FM 2000 radio"
- depends on VIDEO_V4L2 && PCI
- ---help---
- Choose Y here if you have this radio card. This card may also be
- found as Gemtek PCI FM.
-
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
-
- To compile this driver as a module, choose M here: the
- module will be called radio-maxiradio.
-
config RADIO_MIROPCM20
tristate "miroSOUND PCM20 radio"
depends on ISA && ISA_DMA_API && VIDEO_V4L2 && SND
@@ -177,11 +316,6 @@ config RADIO_MIROPCM20
sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this
is required for the radio-miropcm20.
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
-
To compile this driver as a module, choose M here: the
module will be called radio-miropcm20.
@@ -191,11 +325,6 @@ config RADIO_SF16FMI
---help---
Choose Y here if you have one of these FM radio cards.
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
-
To compile this driver as a module, choose M here: the
module will be called radio-sf16fmi.
@@ -205,50 +334,35 @@ config RADIO_SF16FMR2
---help---
Choose Y here if you have one of these FM radio cards.
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found on the WWW at
- <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
To compile this driver as a module, choose M here: the
module will be called radio-sf16fmr2.
config RADIO_TERRATEC
tristate "TerraTec ActiveRadio ISA Standalone"
depends on ISA && VIDEO_V4L2
+ select RADIO_ISA
---help---
- Choose Y here if you have this FM radio card, and then fill in the
- port address below. (TODO)
+ Choose Y here if you have this FM radio card.
- Note: This driver is in its early stages. Right now volume and
- frequency control and muting works at least for me, but
- unfortunately I have not found anybody who wants to use this card
- with Linux. So if it is this what YOU are trying to do right now,
- PLEASE DROP ME A NOTE!! Rolf Offermanns <rolf@offermanns.de>.
-
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
+ Note: this driver hasn't been tested since a long time due to lack
+ of hardware. If you have this hardware, then please contact the
+ linux-media mailinglist.
To compile this driver as a module, choose M here: the
module will be called radio-terratec.
-config RADIO_TERRATEC_PORT
- hex "Terratec i/o port (normally 0x590)"
- depends on RADIO_TERRATEC=y
- default "590"
- help
- Fill in the I/O port of your TerraTec FM radio card. If unsure, go
- with the default.
-
config RADIO_TRUST
tristate "Trust FM radio card"
depends on ISA && VIDEO_V4L2
+ select RADIO_ISA
help
This is a driver for the Trust FM radio cards. Say Y if you have
such a card and want to use it under Linux.
+ Note: this driver hasn't been tested since a long time due to lack
+ of hardware. If you have this hardware, then please contact the
+ linux-media mailinglist.
+
To compile this driver as a module, choose M here: the
module will be called radio-trust.
@@ -263,14 +377,14 @@ config RADIO_TRUST_PORT
config RADIO_TYPHOON
tristate "Typhoon Radio (a.k.a. EcoRadio)"
depends on ISA && VIDEO_V4L2
+ select RADIO_ISA
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address and the frequency used for muting below.
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
+ Note: this driver hasn't been tested since a long time due to lack
+ of hardware. If you have this hardware, then please contact the
+ linux-media mailinglist.
To compile this driver as a module, choose M here: the
module will be called radio-typhoon.
@@ -297,14 +411,14 @@ config RADIO_TYPHOON_MUTEFREQ
config RADIO_ZOLTRIX
tristate "Zoltrix Radio"
depends on ISA && VIDEO_V4L2
+ select RADIO_ISA
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address below.
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
+ Note: this driver hasn't been tested since a long time due to lack
+ of hardware. If you have this hardware, then please contact the
+ linux-media mailinglist.
To compile this driver as a module, choose M here: the
module will be called radio-zoltrix.
@@ -316,130 +430,6 @@ config RADIO_ZOLTRIX_PORT
help
Enter the I/O port of your Zoltrix radio card.
-config I2C_SI4713
- tristate "I2C driver for Silicon Labs Si4713 device"
- depends on I2C && VIDEO_V4L2
- ---help---
- Say Y here if you want support to Si4713 I2C device.
- This device driver supports only i2c bus.
-
- To compile this driver as a module, choose M here: the
- module will be called si4713.
-
-config RADIO_SI4713
- tristate "Silicon Labs Si4713 FM Radio Transmitter support"
- depends on I2C && VIDEO_V4L2
- select I2C_SI4713
- ---help---
- Say Y here if you want support to Si4713 FM Radio Transmitter.
- This device can transmit audio through FM. It can transmit
- RDS and RBDS signals as well. This module is the v4l2 radio
- interface for the i2c driver of this device.
-
- To compile this driver as a module, choose M here: the
- module will be called radio-si4713.
-
-config USB_DSBR
- tristate "D-Link/GemTek USB FM radio support"
- depends on USB && VIDEO_V4L2
- ---help---
- Say Y here if you want to connect this type of radio to your
- computer's USB port. Note that the audio is not digital, and
- you must connect the line out connector to a sound card or a
- set of speakers.
-
- To compile this driver as a module, choose M here: the
- module will be called dsbr100.
-
-config RADIO_SI470X
- bool "Silicon Labs Si470x FM Radio Receiver support"
- depends on VIDEO_V4L2
-
-source "drivers/media/radio/si470x/Kconfig"
-
-config USB_MR800
- tristate "AverMedia MR 800 USB FM radio support"
- depends on USB && VIDEO_V4L2
- ---help---
- Say Y here if you want to connect this type of radio to your
- computer's USB port. Note that the audio is not digital, and
- you must connect the line out connector to a sound card or a
- set of speakers.
-
- To compile this driver as a module, choose M here: the
- module will be called radio-mr800.
-
-config RADIO_TEA5764
- tristate "TEA5764 I2C FM radio support"
- depends on I2C && VIDEO_V4L2
- ---help---
- Say Y here if you want to use the TEA5764 FM chip found in
- EZX phones. This FM chip is present in EZX phones from Motorola,
- connected to internal pxa I2C bus.
-
- To compile this driver as a module, choose M here: the
- module will be called radio-tea5764.
-
-config RADIO_TEA5764_XTAL
- bool "TEA5764 crystal reference"
- depends on RADIO_TEA5764=y
- default y
- help
- Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N
- here if TEA5764 reference frequency is connected in FREQIN.
-
-config RADIO_SAA7706H
- tristate "SAA7706H Car Radio DSP"
- depends on I2C && VIDEO_V4L2
- ---help---
- Say Y here if you want to use the SAA7706H Car radio Digital
- Signal Processor, found for instance on the Russellville development
- board. On the russellville the device is connected to internal
- timberdale I2C bus.
-
- To compile this driver as a module, choose M here: the
- module will be called SAA7706H.
-
-config RADIO_TEF6862
- tristate "TEF6862 Car Radio Enhanced Selectivity Tuner"
- depends on I2C && VIDEO_V4L2
- ---help---
- Say Y here if you want to use the TEF6862 Car Radio Enhanced
- Selectivity Tuner, found for instance on the Russellville development
- board. On the russellville the device is connected to internal
- timberdale I2C bus.
-
- To compile this driver as a module, choose M here: the
- module will be called TEF6862.
-
-config RADIO_TIMBERDALE
- tristate "Enable the Timberdale radio driver"
- depends on MFD_TIMBERDALE && VIDEO_V4L2
- depends on I2C # for RADIO_SAA7706H
- select RADIO_TEF6862
- select RADIO_SAA7706H
- ---help---
- This is a kind of umbrella driver for the Radio Tuner and DSP
- found behind the Timberdale FPGA on the Russellville board.
- Enabling this driver will automatically select the DSP and tuner.
-
-config RADIO_WL1273
- tristate "Texas Instruments WL1273 I2C FM Radio"
- depends on I2C && VIDEO_V4L2
- select MFD_WL1273_CORE
- select FW_LOADER
- ---help---
- Choose Y here if you have this FM radio chip.
-
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux 2 API. Information on
- this API and pointers to "v4l2" programs may be found at
- <file:Documentation/video4linux/API.html>.
-
- To compile this driver as a module, choose M here: the
- module will be called radio-wl1273.
-
-# TI's ST based wl128x FM radio
-source "drivers/media/radio/wl128x/Kconfig"
+endif # V4L_RADIO_ISA_DRIVERS
endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 390daf94d847..ca8c7d134b95 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -2,6 +2,7 @@
# Makefile for the kernel character device drivers.
#
+obj-$(CONFIG_RADIO_ISA) += radio-isa.o
obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
@@ -20,6 +21,7 @@ obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_RADIO_SI470X) += si470x/
obj-$(CONFIG_USB_MR800) += radio-mr800.o
+obj-$(CONFIG_USB_KEENE) += radio-keene.o
obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 1c3f8440a55c..98e0c8c20312 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -1,16 +1,13 @@
-/* radiotrack (radioreveal) driver for Linux radio support
- * (c) 1997 M. Kirkwood
+/*
+ * AimsLab RadioTrack (aka RadioVeveal) driver
+ *
+ * Copyright 1997 M. Kirkwood
+ *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
*
- * History:
- * 1999-02-24 Russell Kroll <rkroll@exploits.org>
- * Fine tuning/VIDEO_TUNER_LOW
- * Frequency range expanded to start at 87 MHz
- *
- * TODO: Allow for more than one of these foolish entities :-)
- *
* Notes on the hardware (reverse engineered from other peoples'
* reverse engineering of AIMS' code :-)
*
@@ -26,6 +23,7 @@
* wait(a_wee_while);
* out(port, stop_changing_the_volume);
*
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
*/
#include <linux/module.h> /* Modules */
@@ -34,401 +32,179 @@
#include <linux/delay.h> /* msleep */
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/io.h> /* outb, outb_p */
+#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include "radio-isa.h"
-MODULE_AUTHOR("M.Kirkwood");
+MODULE_AUTHOR("M. Kirkwood");
MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("1.0.0");
#ifndef CONFIG_RADIO_RTRACK_PORT
#define CONFIG_RADIO_RTRACK_PORT -1
#endif
-static int io = CONFIG_RADIO_RTRACK_PORT;
-static int radio_nr = -1;
+#define RTRACK_MAX 2
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
-module_param(radio_nr, int, 0);
+static int io[RTRACK_MAX] = { [0] = CONFIG_RADIO_RTRACK_PORT,
+ [1 ... (RTRACK_MAX - 1)] = -1 };
+static int radio_nr[RTRACK_MAX] = { [0 ... (RTRACK_MAX - 1)] = -1 };
-struct rtrack
-{
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- int port;
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
+struct rtrack {
+ struct radio_isa_card isa;
int curvol;
- unsigned long curfreq;
- int muted;
- int io;
- struct mutex lock;
};
-static struct rtrack rtrack_card;
-
-/* local things */
-
-static void rt_decvol(struct rtrack *rt)
-{
- outb(0x58, rt->io); /* volume down + sigstr + on */
- msleep(100);
- outb(0xd8, rt->io); /* volume steady + sigstr + on */
-}
-
-static void rt_incvol(struct rtrack *rt)
-{
- outb(0x98, rt->io); /* volume up + sigstr + on */
- msleep(100);
- outb(0xd8, rt->io); /* volume steady + sigstr + on */
-}
-
-static void rt_mute(struct rtrack *rt)
-{
- rt->muted = 1;
- mutex_lock(&rt->lock);
- outb(0xd0, rt->io); /* volume steady, off */
- mutex_unlock(&rt->lock);
-}
-
-static int rt_setvol(struct rtrack *rt, int vol)
+static struct radio_isa_card *rtrack_alloc(void)
{
- int i;
-
- mutex_lock(&rt->lock);
-
- if (vol == rt->curvol) { /* requested volume = current */
- if (rt->muted) { /* user is unmuting the card */
- rt->muted = 0;
- outb(0xd8, rt->io); /* enable card */
- }
- mutex_unlock(&rt->lock);
- return 0;
- }
-
- if (vol == 0) { /* volume = 0 means mute the card */
- outb(0x48, rt->io); /* volume down but still "on" */
- msleep(2000); /* make sure it's totally down */
- outb(0xd0, rt->io); /* volume steady, off */
- rt->curvol = 0; /* track the volume state! */
- mutex_unlock(&rt->lock);
- return 0;
- }
+ struct rtrack *rt = kzalloc(sizeof(struct rtrack), GFP_KERNEL);
- rt->muted = 0;
- if (vol > rt->curvol)
- for (i = rt->curvol; i < vol; i++)
- rt_incvol(rt);
- else
- for (i = rt->curvol; i > vol; i--)
- rt_decvol(rt);
-
- rt->curvol = vol;
- mutex_unlock(&rt->lock);
- return 0;
+ if (rt)
+ rt->curvol = 0xff;
+ return rt ? &rt->isa : NULL;
}
-/* the 128+64 on these outb's is to keep the volume stable while tuning
- * without them, the volume _will_ creep up with each frequency change
- * and bit 4 (+16) is to keep the signal strength meter enabled
+/* The 128+64 on these outb's is to keep the volume stable while tuning.
+ * Without them, the volume _will_ creep up with each frequency change
+ * and bit 4 (+16) is to keep the signal strength meter enabled.
*/
-static void send_0_byte(struct rtrack *rt)
+static void send_0_byte(struct radio_isa_card *isa, int on)
{
- if (rt->curvol == 0 || rt->muted) {
- outb_p(128+64+16+ 1, rt->io); /* wr-enable + data low */
- outb_p(128+64+16+2+1, rt->io); /* clock */
- }
- else {
- outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */
- outb_p(128+64+16+8+2+1, rt->io); /* clock */
- }
+ outb_p(128+64+16+on+1, isa->io); /* wr-enable + data low */
+ outb_p(128+64+16+on+2+1, isa->io); /* clock */
msleep(1);
}
-static void send_1_byte(struct rtrack *rt)
+static void send_1_byte(struct radio_isa_card *isa, int on)
{
- if (rt->curvol == 0 || rt->muted) {
- outb_p(128+64+16+4 +1, rt->io); /* wr-enable+data high */
- outb_p(128+64+16+4+2+1, rt->io); /* clock */
- }
- else {
- outb_p(128+64+16+8+4 +1, rt->io); /* on+wr-enable+data high */
- outb_p(128+64+16+8+4+2+1, rt->io); /* clock */
- }
-
+ outb_p(128+64+16+on+4+1, isa->io); /* wr-enable+data high */
+ outb_p(128+64+16+on+4+2+1, isa->io); /* clock */
msleep(1);
}
-static int rt_setfreq(struct rtrack *rt, unsigned long freq)
+static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq)
{
+ int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8;
int i;
- mutex_lock(&rt->lock); /* Stop other ops interfering */
-
- rt->curfreq = freq;
-
- /* now uses VIDEO_TUNER_LOW for fine tuning */
-
freq += 171200; /* Add 10.7 MHz IF */
freq /= 800; /* Convert to 50 kHz units */
- send_0_byte(rt); /* 0: LSB of frequency */
+ send_0_byte(isa, on); /* 0: LSB of frequency */
for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
if (freq & (1 << i))
- send_1_byte(rt);
+ send_1_byte(isa, on);
else
- send_0_byte(rt);
-
- send_0_byte(rt); /* 14: test bit - always 0 */
- send_0_byte(rt); /* 15: test bit - always 0 */
-
- send_0_byte(rt); /* 16: band data 0 - always 0 */
- send_0_byte(rt); /* 17: band data 1 - always 0 */
- send_0_byte(rt); /* 18: band data 2 - always 0 */
- send_0_byte(rt); /* 19: time base - always 0 */
-
- send_0_byte(rt); /* 20: spacing (0 = 25 kHz) */
- send_1_byte(rt); /* 21: spacing (1 = 25 kHz) */
- send_0_byte(rt); /* 22: spacing (0 = 25 kHz) */
- send_1_byte(rt); /* 23: AM/FM (FM = 1, always) */
-
- if (rt->curvol == 0 || rt->muted)
- outb(0xd0, rt->io); /* volume steady + sigstr */
- else
- outb(0xd8, rt->io); /* volume steady + sigstr + on */
-
- mutex_unlock(&rt->lock);
-
- return 0;
-}
-
-static int rt_getsigstr(struct rtrack *rt)
-{
- int sig = 1;
-
- mutex_lock(&rt->lock);
- if (inb(rt->io) & 2) /* bit set = no signal present */
- sig = 0;
- mutex_unlock(&rt->lock);
- return sig;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- strlcpy(v->driver, "radio-aimslab", sizeof(v->driver));
- strlcpy(v->card, "RadioTrack", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- struct rtrack *rt = video_drvdata(file);
+ send_0_byte(isa, on);
- if (v->index > 0)
- return -EINVAL;
+ send_0_byte(isa, on); /* 14: test bit - always 0 */
+ send_0_byte(isa, on); /* 15: test bit - always 0 */
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = 87 * 16000;
- v->rangehigh = 108 * 16000;
- v->rxsubchans = V4L2_TUNER_SUB_MONO;
- v->capability = V4L2_TUNER_CAP_LOW;
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xffff * rt_getsigstr(rt);
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct rtrack *rt = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- rt_setfreq(rt, f->frequency);
- return 0;
-}
+ send_0_byte(isa, on); /* 16: band data 0 - always 0 */
+ send_0_byte(isa, on); /* 17: band data 1 - always 0 */
+ send_0_byte(isa, on); /* 18: band data 2 - always 0 */
+ send_0_byte(isa, on); /* 19: time base - always 0 */
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct rtrack *rt = video_drvdata(file);
+ send_0_byte(isa, on); /* 20: spacing (0 = 25 kHz) */
+ send_1_byte(isa, on); /* 21: spacing (1 = 25 kHz) */
+ send_0_byte(isa, on); /* 22: spacing (0 = 25 kHz) */
+ send_1_byte(isa, on); /* 23: AM/FM (FM = 1, always) */
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = rt->curfreq;
+ outb(0xd0 + on, isa->io); /* volume steady + sigstr */
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
+static u32 rtrack_g_signal(struct radio_isa_card *isa)
{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
- }
- return -EINVAL;
+ /* bit set = no signal present */
+ return 0xffff * !(inb(isa->io) & 2);
}
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int rtrack_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
{
- struct rtrack *rt = video_drvdata(file);
+ struct rtrack *rt = container_of(isa, struct rtrack, isa);
+ int curvol = rt->curvol;
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = rt->muted;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = rt->curvol;
+ if (mute) {
+ outb(0xd0, isa->io); /* volume steady + sigstr + off */
return 0;
}
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct rtrack *rt = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- rt_mute(rt);
- else
- rt_setvol(rt, rt->curvol);
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- rt_setvol(rt, ctrl->value);
- return 0;
+ if (vol == 0) { /* volume = 0 means mute the card */
+ outb(0x48, isa->io); /* volume down but still "on" */
+ msleep(curvol * 3); /* make sure it's totally down */
+ } else if (curvol < vol) {
+ outb(0x98, isa->io); /* volume up + sigstr + on */
+ for (; curvol < vol; curvol++)
+ udelay(3000);
+ } else if (curvol > vol) {
+ outb(0x58, isa->io); /* volume down + sigstr + on */
+ for (; curvol > vol; curvol--)
+ udelay(3000);
}
- return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
+ outb(0xd8, isa->io); /* volume steady + sigstr + on */
+ rt->curvol = vol;
return 0;
}
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+/* Mute card - prevents noisy bootups */
+static int rtrack_initialize(struct radio_isa_card *isa)
{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
+ /* this ensures that the volume is all the way up */
+ outb(0x90, isa->io); /* volume up but still "on" */
+ msleep(3000); /* make sure it's totally up */
+ outb(0xc0, isa->io); /* steady volume, mute card */
return 0;
}
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations rtrack_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops rtrack_ops = {
+ .alloc = rtrack_alloc,
+ .init = rtrack_initialize,
+ .s_mute_volume = rtrack_s_mute_volume,
+ .s_frequency = rtrack_s_frequency,
+ .g_signal = rtrack_g_signal,
};
-static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
+static const int rtrack_ioports[] = { 0x20f, 0x30f };
+
+static struct radio_isa_driver rtrack_driver = {
+ .driver = {
+ .match = radio_isa_match,
+ .probe = radio_isa_probe,
+ .remove = radio_isa_remove,
+ .driver = {
+ .name = "radio-aimslab",
+ },
+ },
+ .io_params = io,
+ .radio_nr_params = radio_nr,
+ .io_ports = rtrack_ioports,
+ .num_of_io_ports = ARRAY_SIZE(rtrack_ioports),
+ .region_size = 2,
+ .card = "AIMSlab RadioTrack/RadioReveal",
+ .ops = &rtrack_ops,
+ .has_stereo = true,
+ .max_volume = 0xff,
};
static int __init rtrack_init(void)
{
- struct rtrack *rt = &rtrack_card;
- struct v4l2_device *v4l2_dev = &rt->v4l2_dev;
- int res;
-
- strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name));
- rt->io = io;
-
- if (rt->io == -1) {
- v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n");
- return -EINVAL;
- }
-
- if (!request_region(rt->io, 2, "rtrack")) {
- v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io);
- return -EBUSY;
- }
-
- res = v4l2_device_register(NULL, v4l2_dev);
- if (res < 0) {
- release_region(rt->io, 2);
- v4l2_err(v4l2_dev, "could not register v4l2_device\n");
- return res;
- }
-
- strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name));
- rt->vdev.v4l2_dev = v4l2_dev;
- rt->vdev.fops = &rtrack_fops;
- rt->vdev.ioctl_ops = &rtrack_ioctl_ops;
- rt->vdev.release = video_device_release_empty;
- video_set_drvdata(&rt->vdev, rt);
-
- /* Set up the I/O locking */
-
- mutex_init(&rt->lock);
-
- /* mute card - prevents noisy bootups */
-
- /* this ensures that the volume is all the way down */
- outb(0x48, rt->io); /* volume down but still "on" */
- msleep(2000); /* make sure it's totally down */
- outb(0xc0, rt->io); /* steady volume, mute card */
-
- if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(&rt->v4l2_dev);
- release_region(rt->io, 2);
- return -EINVAL;
- }
- v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
-
- return 0;
+ return isa_register_driver(&rtrack_driver.driver, RTRACK_MAX);
}
static void __exit rtrack_exit(void)
{
- struct rtrack *rt = &rtrack_card;
-
- video_unregister_device(&rt->vdev);
- v4l2_device_unregister(&rt->v4l2_dev);
- release_region(rt->io, 2);
+ isa_unregister_driver(&rtrack_driver.driver);
}
module_init(rtrack_init);
module_exit(rtrack_exit);
-
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index eed7b0840734..177bcbd7a7c1 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -1,5 +1,7 @@
-/* radio-aztech.c - Aztech radio card driver for Linux 2.2
+/*
+ * radio-aztech.c - Aztech radio card driver
*
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@xs4all.nl>
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
* Adapted to support the Video for Linux API by
* Russell Kroll <rkroll@exploits.org>. Based on original tuner code by:
@@ -10,19 +12,7 @@
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
- * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
- * along with more information on the card itself.
- *
- * History:
- * 1999-02-24 Russell Kroll <rkroll@exploits.org>
- * Fine tuning/VIDEO_TUNER_LOW
- * Range expanded to 87-108 MHz (from 87.9-107.8)
- *
- * Notable changes from the original source:
- * - includes stripped down to the essentials
- * - for loops used as delays replaced with udelay()
- * - #defines removed, changed to static values
- * - tuning structure changed - no more character arrays, other changes
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
*/
#include <linux/module.h> /* Modules */
@@ -31,126 +21,72 @@
#include <linux/delay.h> /* udelay */
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/io.h> /* outb, outb_p */
+#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include "radio-isa.h"
MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
MODULE_DESCRIPTION("A driver for the Aztech radio card.");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("1.0.0");
/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
-
#ifndef CONFIG_RADIO_AZTECH_PORT
#define CONFIG_RADIO_AZTECH_PORT -1
#endif
-static int io = CONFIG_RADIO_AZTECH_PORT;
-static int radio_nr = -1;
-static int radio_wait_time = 1000;
+#define AZTECH_MAX 2
-module_param(io, int, 0);
-module_param(radio_nr, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
+static int io[AZTECH_MAX] = { [0] = CONFIG_RADIO_AZTECH_PORT,
+ [1 ... (AZTECH_MAX - 1)] = -1 };
+static int radio_nr[AZTECH_MAX] = { [0 ... (AZTECH_MAX - 1)] = -1 };
+static const int radio_wait_time = 1000;
-struct aztech
-{
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- int io;
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Aztech card (0x350 or 0x358)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
+struct aztech {
+ struct radio_isa_card isa;
int curvol;
- unsigned long curfreq;
- int stereo;
- struct mutex lock;
};
-static struct aztech aztech_card;
-
-static int volconvert(int level)
-{
- level >>= 14; /* Map 16bits down to 2 bit */
- level &= 3;
-
- /* convert to card-friendly values */
- switch (level) {
- case 0:
- return 0;
- case 1:
- return 1;
- case 2:
- return 4;
- case 3:
- return 5;
- }
- return 0; /* Quieten gcc */
-}
-
static void send_0_byte(struct aztech *az)
{
udelay(radio_wait_time);
- outb_p(2 + volconvert(az->curvol), az->io);
- outb_p(64 + 2 + volconvert(az->curvol), az->io);
+ outb_p(2 + az->curvol, az->isa.io);
+ outb_p(64 + 2 + az->curvol, az->isa.io);
}
static void send_1_byte(struct aztech *az)
{
- udelay (radio_wait_time);
- outb_p(128 + 2 + volconvert(az->curvol), az->io);
- outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io);
-}
-
-static int az_setvol(struct aztech *az, int vol)
-{
- mutex_lock(&az->lock);
- outb(volconvert(vol), az->io);
- mutex_unlock(&az->lock);
- return 0;
-}
-
-/* thanks to Michael Dwyer for giving me a dose of clues in
- * the signal strength department..
- *
- * This card has a stereo bit - bit 0 set = mono, not set = stereo
- * It also has a "signal" bit - bit 1 set = bad signal, not set = good
- *
- */
-
-static int az_getsigstr(struct aztech *az)
-{
- int sig = 1;
-
- mutex_lock(&az->lock);
- if (inb(az->io) & 2) /* bit set = no signal present */
- sig = 0;
- mutex_unlock(&az->lock);
- return sig;
+ udelay(radio_wait_time);
+ outb_p(128 + 2 + az->curvol, az->isa.io);
+ outb_p(128 + 64 + 2 + az->curvol, az->isa.io);
}
-static int az_getstereo(struct aztech *az)
+static struct radio_isa_card *aztech_alloc(void)
{
- int stereo = 1;
+ struct aztech *az = kzalloc(sizeof(*az), GFP_KERNEL);
- mutex_lock(&az->lock);
- if (inb(az->io) & 1) /* bit set = mono */
- stereo = 0;
- mutex_unlock(&az->lock);
- return stereo;
+ return az ? &az->isa : NULL;
}
-static int az_setfreq(struct aztech *az, unsigned long frequency)
+static int aztech_s_frequency(struct radio_isa_card *isa, u32 freq)
{
+ struct aztech *az = container_of(isa, struct aztech, isa);
int i;
- mutex_lock(&az->lock);
-
- az->curfreq = frequency;
- frequency += 171200; /* Add 10.7 MHz IF */
- frequency /= 800; /* Convert to 50 kHz units */
+ freq += 171200; /* Add 10.7 MHz IF */
+ freq /= 800; /* Convert to 50 kHz units */
send_0_byte(az); /* 0: LSB of frequency */
for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
- if (frequency & (1 << i))
+ if (freq & (1 << i))
send_1_byte(az);
else
send_0_byte(az);
@@ -158,7 +94,7 @@ static int az_setfreq(struct aztech *az, unsigned long frequency)
send_0_byte(az); /* 14: test bit - always 0 */
send_0_byte(az); /* 15: test bit - always 0 */
send_0_byte(az); /* 16: band data 0 - always 0 */
- if (az->stereo) /* 17: stereo (1 to enable) */
+ if (isa->stereo) /* 17: stereo (1 to enable) */
send_1_byte(az);
else
send_0_byte(az);
@@ -173,225 +109,77 @@ static int az_setfreq(struct aztech *az, unsigned long frequency)
/* latch frequency */
udelay(radio_wait_time);
- outb_p(128 + 64 + volconvert(az->curvol), az->io);
-
- mutex_unlock(&az->lock);
-
- return 0;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- strlcpy(v->driver, "radio-aztech", sizeof(v->driver));
- strlcpy(v->card, "Aztech Radio", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- struct aztech *az = video_drvdata(file);
-
- if (v->index > 0)
- return -EINVAL;
-
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
-
- v->rangelow = 87 * 16000;
- v->rangehigh = 108 * 16000;
- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- v->capability = V4L2_TUNER_CAP_LOW;
- if (az_getstereo(az))
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xFFFF * az_getsigstr(az);
-
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- return v->index ? -EINVAL : 0;
-}
+ outb_p(128 + 64 + az->curvol, az->isa.io);
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
return 0;
}
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
+/* thanks to Michael Dwyer for giving me a dose of clues in
+ * the signal strength department..
+ *
+ * This card has a stereo bit - bit 0 set = mono, not set = stereo
+ */
+static u32 aztech_g_rxsubchans(struct radio_isa_card *isa)
{
- return a->index ? -EINVAL : 0;
+ if (inb(isa->io) & 1)
+ return V4L2_TUNER_SUB_MONO;
+ return V4L2_TUNER_SUB_STEREO;
}
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+static int aztech_s_stereo(struct radio_isa_card *isa, bool stereo)
{
- struct aztech *az = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- az_setfreq(az, f->frequency);
- return 0;
+ return aztech_s_frequency(isa, isa->freq);
}
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+static int aztech_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
{
- struct aztech *az = video_drvdata(file);
+ struct aztech *az = container_of(isa, struct aztech, isa);
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = az->curfreq;
+ if (mute)
+ vol = 0;
+ az->curvol = (vol & 1) + ((vol & 2) << 1);
+ outb(az->curvol, isa->io);
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct aztech *az = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (az->curvol == 0)
- ctrl->value = 1;
- else
- ctrl->value = 0;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = az->curvol * 6554;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct aztech *az = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- az_setvol(az, 0);
- else
- az_setvol(az, az->curvol);
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- az_setvol(az, ctrl->value);
- return 0;
- }
- return -EINVAL;
-}
-
-static const struct v4l2_file_operations aztech_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops aztech_ops = {
+ .alloc = aztech_alloc,
+ .s_mute_volume = aztech_s_mute_volume,
+ .s_frequency = aztech_s_frequency,
+ .s_stereo = aztech_s_stereo,
+ .g_rxsubchans = aztech_g_rxsubchans,
};
-static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
+static const int aztech_ioports[] = { 0x350, 0x358 };
+
+static struct radio_isa_driver aztech_driver = {
+ .driver = {
+ .match = radio_isa_match,
+ .probe = radio_isa_probe,
+ .remove = radio_isa_remove,
+ .driver = {
+ .name = "radio-aztech",
+ },
+ },
+ .io_params = io,
+ .radio_nr_params = radio_nr,
+ .io_ports = aztech_ioports,
+ .num_of_io_ports = ARRAY_SIZE(aztech_ioports),
+ .region_size = 2,
+ .card = "Aztech Radio",
+ .ops = &aztech_ops,
+ .has_stereo = true,
+ .max_volume = 3,
};
static int __init aztech_init(void)
{
- struct aztech *az = &aztech_card;
- struct v4l2_device *v4l2_dev = &az->v4l2_dev;
- int res;
-
- strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name));
- az->io = io;
-
- if (az->io == -1) {
- v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n");
- return -EINVAL;
- }
-
- if (!request_region(az->io, 2, "aztech")) {
- v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io);
- return -EBUSY;
- }
-
- res = v4l2_device_register(NULL, v4l2_dev);
- if (res < 0) {
- release_region(az->io, 2);
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- return res;
- }
-
- mutex_init(&az->lock);
- strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name));
- az->vdev.v4l2_dev = v4l2_dev;
- az->vdev.fops = &aztech_fops;
- az->vdev.ioctl_ops = &aztech_ioctl_ops;
- az->vdev.release = video_device_release_empty;
- video_set_drvdata(&az->vdev, az);
- /* mute card - prevents noisy bootups */
- outb(0, az->io);
-
- if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(az->io, 2);
- return -EINVAL;
- }
-
- v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
- return 0;
+ return isa_register_driver(&aztech_driver.driver, AZTECH_MAX);
}
static void __exit aztech_exit(void)
{
- struct aztech *az = &aztech_card;
-
- video_unregister_device(&az->vdev);
- v4l2_device_unregister(&az->v4l2_dev);
- release_region(az->io, 2);
+ isa_unregister_driver(&aztech_driver.driver);
}
module_init(aztech_init);
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index edadc8449a3d..2e639ce6f256 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -1,4 +1,7 @@
-/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin <jmunsin@iki.fi>
+/*
+ * GemTek radio card driver
+ *
+ * Copyright 1998 Jonas Munsin <jmunsin@iki.fi>
*
* GemTek hasn't released any specs on the card, so the protocol had to
* be reverse engineered with dosemu.
@@ -11,9 +14,12 @@
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
*
- * TODO: Allow for more than one of these foolish entities :-)
- *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Note: this card seems to swap the left and right audio channels!
+ *
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
*/
#include <linux/module.h> /* Modules */
@@ -23,8 +29,10 @@
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/mutex.h>
#include <linux/io.h> /* outb, outb_p */
+#include <linux/slab.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
+#include "radio-isa.h"
/*
* Module info.
@@ -33,7 +41,7 @@
MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
MODULE_DESCRIPTION("A driver for the GemTek Radio card.");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.4");
+MODULE_VERSION("1.0.0");
/*
* Module params.
@@ -46,45 +54,29 @@ MODULE_VERSION("0.0.4");
#define CONFIG_RADIO_GEMTEK_PROBE 1
#endif
-static int io = CONFIG_RADIO_GEMTEK_PORT;
-static int probe = CONFIG_RADIO_GEMTEK_PROBE;
-static int hardmute;
-static int shutdown = 1;
-static int keepmuted = 1;
-static int initmute = 1;
-static int radio_nr = -1;
+#define GEMTEK_MAX 4
-module_param(io, int, 0444);
-MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
- "probing is disabled or fails. The most common I/O ports are: 0x20c "
- "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
- "work for the combined sound/radiocard).");
+static bool probe = CONFIG_RADIO_GEMTEK_PROBE;
+static bool hardmute;
+static int io[GEMTEK_MAX] = { [0] = CONFIG_RADIO_GEMTEK_PORT,
+ [1 ... (GEMTEK_MAX - 1)] = -1 };
+static int radio_nr[GEMTEK_MAX] = { [0 ... (GEMTEK_MAX - 1)] = -1 };
module_param(probe, bool, 0444);
-MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
- "common I/O ports used by the card are probed.");
+MODULE_PARM_DESC(probe, "Enable automatic device probing.");
module_param(hardmute, bool, 0644);
-MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may "
+MODULE_PARM_DESC(hardmute, "Enable 'hard muting' by shutting down PLL, may "
"reduce static noise.");
-module_param(shutdown, bool, 0644);
-MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when "
- "module is unloaded.");
-
-module_param(keepmuted, bool, 0644);
-MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed.");
-
-module_param(initmute, bool, 0444);
-MODULE_PARM_DESC(initmute, "Mute card when module is loaded.");
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "Force I/O ports for the GemTek Radio card if automatic "
+ "probing is disabled or fails. The most common I/O ports are: 0x20c "
+ "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
+ "work for the combined sound/radiocard).");
-module_param(radio_nr, int, 0444);
-
-/*
- * Functions for controlling the card.
- */
-#define GEMTEK_LOWFREQ (87*16000)
-#define GEMTEK_HIGHFREQ (108*16000)
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
/*
* Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal
@@ -108,18 +100,11 @@ module_param(radio_nr, int, 0444);
#define LONG_DELAY 75 /* usec */
struct gemtek {
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- struct mutex lock;
- unsigned long lastfreq;
- int muted;
- int verified;
- int io;
+ struct radio_isa_card isa;
+ bool muted;
u32 bu2614data;
};
-static struct gemtek gemtek_card;
-
#define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */
#define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */
#define BU2614_VOID_BITS 4 /* unused */
@@ -166,31 +151,24 @@ static struct gemtek gemtek_card;
*/
static void gemtek_bu2614_transmit(struct gemtek *gt)
{
+ struct radio_isa_card *isa = &gt->isa;
int i, bit, q, mute;
- mutex_lock(&gt->lock);
-
mute = gt->muted ? GEMTEK_MT : 0x00;
- outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io);
- udelay(SHORT_DELAY);
- outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io);
+ outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, isa->io);
udelay(LONG_DELAY);
for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) {
bit = (q & 1) ? GEMTEK_DA : 0;
- outb_p(mute | GEMTEK_CE | bit, gt->io);
+ outb_p(mute | GEMTEK_CE | bit, isa->io);
udelay(SHORT_DELAY);
- outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io);
+ outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, isa->io);
udelay(SHORT_DELAY);
}
- outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io);
+ outb_p(mute | GEMTEK_DA | GEMTEK_CK, isa->io);
udelay(SHORT_DELAY);
- outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io);
- udelay(LONG_DELAY);
-
- mutex_unlock(&gt->lock);
}
/*
@@ -198,21 +176,27 @@ static void gemtek_bu2614_transmit(struct gemtek *gt)
*/
static unsigned long gemtek_convfreq(unsigned long freq)
{
- return ((freq<<FSCALE) + IF_OFFSET + REF_FREQ/2) / REF_FREQ;
+ return ((freq << FSCALE) + IF_OFFSET + REF_FREQ / 2) / REF_FREQ;
+}
+
+static struct radio_isa_card *gemtek_alloc(void)
+{
+ struct gemtek *gt = kzalloc(sizeof(*gt), GFP_KERNEL);
+
+ if (gt)
+ gt->muted = true;
+ return gt ? &gt->isa : NULL;
}
/*
* Set FM-frequency.
*/
-static void gemtek_setfreq(struct gemtek *gt, unsigned long freq)
+static int gemtek_s_frequency(struct radio_isa_card *isa, u32 freq)
{
- if (keepmuted && hardmute && gt->muted)
- return;
+ struct gemtek *gt = container_of(isa, struct gemtek, isa);
- freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ);
-
- gt->lastfreq = freq;
- gt->muted = 0;
+ if (hardmute && gt->muted)
+ return 0;
gemtek_bu2614_set(gt, BU2614_PORT, 0);
gemtek_bu2614_set(gt, BU2614_FMES, 0);
@@ -220,23 +204,25 @@ static void gemtek_setfreq(struct gemtek *gt, unsigned long freq)
gemtek_bu2614_set(gt, BU2614_SWAL, 0);
gemtek_bu2614_set(gt, BU2614_FMUN, 1); /* GT bit set */
gemtek_bu2614_set(gt, BU2614_TEST, 0);
-
gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq));
-
gemtek_bu2614_transmit(gt);
+ return 0;
}
/*
* Set mute flag.
*/
-static void gemtek_mute(struct gemtek *gt)
+static int gemtek_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
{
+ struct gemtek *gt = container_of(isa, struct gemtek, isa);
int i;
- gt->muted = 1;
-
+ gt->muted = mute;
if (hardmute) {
+ if (!mute)
+ return gemtek_s_frequency(isa, isa->freq);
+
/* Turn off PLL, disable data output */
gemtek_bu2614_set(gt, BU2614_PORT, 0);
gemtek_bu2614_set(gt, BU2614_FMES, 0); /* CT bit off */
@@ -247,367 +233,85 @@ static void gemtek_mute(struct gemtek *gt)
gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF);
gemtek_bu2614_set(gt, BU2614_FREQ, 0);
gemtek_bu2614_transmit(gt);
- return;
+ return 0;
}
- mutex_lock(&gt->lock);
-
/* Read bus contents (CE, CK and DA). */
- i = inb_p(gt->io);
+ i = inb_p(isa->io);
/* Write it back with mute flag set. */
- outb_p((i >> 5) | GEMTEK_MT, gt->io);
+ outb_p((i >> 5) | (mute ? GEMTEK_MT : 0), isa->io);
udelay(SHORT_DELAY);
-
- mutex_unlock(&gt->lock);
-}
-
-/*
- * Unset mute flag.
- */
-static void gemtek_unmute(struct gemtek *gt)
-{
- int i;
-
- gt->muted = 0;
- if (hardmute) {
- /* Turn PLL back on. */
- gemtek_setfreq(gt, gt->lastfreq);
- return;
- }
- mutex_lock(&gt->lock);
-
- i = inb_p(gt->io);
- outb_p(i >> 5, gt->io);
- udelay(SHORT_DELAY);
-
- mutex_unlock(&gt->lock);
+ return 0;
}
-/*
- * Get signal strength (= stereo status).
- */
-static inline int gemtek_getsigstr(struct gemtek *gt)
+static u32 gemtek_g_rxsubchans(struct radio_isa_card *isa)
{
- int sig;
-
- mutex_lock(&gt->lock);
- sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1;
- mutex_unlock(&gt->lock);
- return sig;
+ if (inb_p(isa->io) & GEMTEK_NS)
+ return V4L2_TUNER_SUB_MONO;
+ return V4L2_TUNER_SUB_STEREO;
}
/*
* Check if requested card acts like GemTek Radio card.
*/
-static int gemtek_verify(struct gemtek *gt, int port)
+static bool gemtek_probe(struct radio_isa_card *isa, int io)
{
int i, q;
- if (gt->verified == port)
- return 1;
-
- mutex_lock(&gt->lock);
-
- q = inb_p(port); /* Read bus contents before probing. */
+ q = inb_p(io); /* Read bus contents before probing. */
/* Try to turn on CE, CK and DA respectively and check if card responds
properly. */
for (i = 0; i < 3; ++i) {
- outb_p(1 << i, port);
+ outb_p(1 << i, io);
udelay(SHORT_DELAY);
- if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) {
- mutex_unlock(&gt->lock);
- return 0;
- }
+ if ((inb_p(io) & ~GEMTEK_NS) != (0x17 | (1 << (i + 5))))
+ return false;
}
- outb_p(q >> 5, port); /* Write bus contents back. */
+ outb_p(q >> 5, io); /* Write bus contents back. */
udelay(SHORT_DELAY);
-
- mutex_unlock(&gt->lock);
- gt->verified = port;
-
- return 1;
-}
-
-/*
- * Automatic probing for card.
- */
-static int gemtek_probe(struct gemtek *gt)
-{
- struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
- int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
- int i;
-
- if (!probe) {
- v4l2_info(v4l2_dev, "Automatic device probing disabled.\n");
- return -1;
- }
-
- v4l2_info(v4l2_dev, "Automatic device probing enabled.\n");
-
- for (i = 0; i < ARRAY_SIZE(ioports); ++i) {
- v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]);
-
- if (!request_region(ioports[i], 1, "gemtek-probe")) {
- v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n",
- ioports[i]);
- continue;
- }
-
- if (gemtek_verify(gt, ioports[i])) {
- v4l2_info(v4l2_dev, "Card found from I/O port "
- "0x%x!\n", ioports[i]);
-
- release_region(ioports[i], 1);
- gt->io = ioports[i];
- return gt->io;
- }
-
- release_region(ioports[i], 1);
- }
-
- v4l2_err(v4l2_dev, "Automatic probing failed!\n");
- return -1;
+ return true;
}
-/*
- * Video 4 Linux stuff.
- */
-
-static const struct v4l2_file_operations gemtek_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops gemtek_ops = {
+ .alloc = gemtek_alloc,
+ .probe = gemtek_probe,
+ .s_mute_volume = gemtek_s_mute_volume,
+ .s_frequency = gemtek_s_frequency,
+ .g_rxsubchans = gemtek_g_rxsubchans,
};
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
- strlcpy(v->card, "GemTek", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
-{
- struct gemtek *gt = video_drvdata(file);
-
- if (v->index > 0)
- return -EINVAL;
-
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = GEMTEK_LOWFREQ;
- v->rangehigh = GEMTEK_HIGHFREQ;
- v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
- v->signal = 0xffff * gemtek_getsigstr(gt);
- if (v->signal) {
- v->audmode = V4L2_TUNER_MODE_STEREO;
- v->rxsubchans = V4L2_TUNER_SUB_STEREO;
- } else {
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->rxsubchans = V4L2_TUNER_SUB_MONO;
- }
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
-{
- return (v->index != 0) ? -EINVAL : 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct gemtek *gt = video_drvdata(file);
-
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = gt->lastfreq;
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct gemtek *gt = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- gemtek_setfreq(gt, f->frequency);
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
- default:
- return -EINVAL;
- }
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct gemtek *gt = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = gt->muted;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct gemtek *gt = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- gemtek_mute(gt);
- else
- gemtek_unmute(gt);
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return (i != 0) ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- return (a->index != 0) ? -EINVAL : 0;
-}
-
-static const struct v4l2_ioctl_ops gemtek_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl
+static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
+
+static struct radio_isa_driver gemtek_driver = {
+ .driver = {
+ .match = radio_isa_match,
+ .probe = radio_isa_probe,
+ .remove = radio_isa_remove,
+ .driver = {
+ .name = "radio-gemtek",
+ },
+ },
+ .io_params = io,
+ .radio_nr_params = radio_nr,
+ .io_ports = gemtek_ioports,
+ .num_of_io_ports = ARRAY_SIZE(gemtek_ioports),
+ .region_size = 1,
+ .card = "GemTek Radio",
+ .ops = &gemtek_ops,
+ .has_stereo = true,
};
-/*
- * Initialization / cleanup related stuff.
- */
-
static int __init gemtek_init(void)
{
- struct gemtek *gt = &gemtek_card;
- struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
- int res;
-
- strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name));
-
- v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n");
-
- mutex_init(&gt->lock);
-
- gt->verified = -1;
- gt->io = io;
- gemtek_probe(gt);
- if (gt->io) {
- if (!request_region(gt->io, 1, "gemtek")) {
- v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io);
- return -EBUSY;
- }
-
- if (!gemtek_verify(gt, gt->io))
- v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not "
- "respond properly, check your "
- "configuration.\n", gt->io);
- else
- v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io);
- } else if (probe) {
- v4l2_err(v4l2_dev, "Automatic probing failed and no "
- "fixed I/O port defined.\n");
- return -ENODEV;
- } else {
- v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed "
- "I/O port defined.");
- return -EINVAL;
- }
-
- res = v4l2_device_register(NULL, v4l2_dev);
- if (res < 0) {
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- release_region(gt->io, 1);
- return res;
- }
-
- strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name));
- gt->vdev.v4l2_dev = v4l2_dev;
- gt->vdev.fops = &gemtek_fops;
- gt->vdev.ioctl_ops = &gemtek_ioctl_ops;
- gt->vdev.release = video_device_release_empty;
- video_set_drvdata(&gt->vdev, gt);
-
- /* Set defaults */
- gt->lastfreq = GEMTEK_LOWFREQ;
- gt->bu2614data = 0;
-
- if (initmute)
- gemtek_mute(gt);
-
- if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(gt->io, 1);
- return -EBUSY;
- }
-
- return 0;
+ gemtek_driver.probe = probe;
+ return isa_register_driver(&gemtek_driver.driver, GEMTEK_MAX);
}
-/*
- * Module cleanup
- */
static void __exit gemtek_exit(void)
{
- struct gemtek *gt = &gemtek_card;
- struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
-
- if (shutdown) {
- hardmute = 1; /* Turn off PLL */
- gemtek_mute(gt);
- } else {
- v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n");
- }
-
- video_unregister_device(&gt->vdev);
- v4l2_device_unregister(&gt->v4l2_dev);
- release_region(gt->io, 1);
+ hardmute = 1; /* Turn off PLL */
+ isa_unregister_driver(&gemtek_driver.driver);
}
module_init(gemtek_init);
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
new file mode 100644
index 000000000000..06f906351fad
--- /dev/null
+++ b/drivers/media/radio/radio-isa.c
@@ -0,0 +1,340 @@
+/*
+ * Framework for ISA radio drivers.
+ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers
+ * to concentrate on the actual hardware operation.
+ *
+ * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com>
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+
+#include "radio-isa.h"
+
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_DESCRIPTION("A framework for ISA radio drivers.");
+MODULE_LICENSE("GPL");
+
+#define FREQ_LOW (87U * 16000U)
+#define FREQ_HIGH (108U * 16000U)
+
+static int radio_isa_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+{
+ struct radio_isa_card *isa = video_drvdata(file);
+
+ strlcpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver));
+ strlcpy(v->card, isa->drv->card, sizeof(v->card));
+ snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name);
+
+ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ v->device_caps = v->capabilities | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int radio_isa_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ struct radio_isa_card *isa = video_drvdata(file);
+ const struct radio_isa_ops *ops = isa->drv->ops;
+
+ if (v->index > 0)
+ return -EINVAL;
+
+ strlcpy(v->name, "FM", sizeof(v->name));
+ v->type = V4L2_TUNER_RADIO;
+ v->rangelow = FREQ_LOW;
+ v->rangehigh = FREQ_HIGH;
+ v->capability = V4L2_TUNER_CAP_LOW;
+ if (isa->drv->has_stereo)
+ v->capability |= V4L2_TUNER_CAP_STEREO;
+
+ if (ops->g_rxsubchans)
+ v->rxsubchans = ops->g_rxsubchans(isa);
+ else
+ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ v->audmode = isa->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+ if (ops->g_signal)
+ v->signal = ops->g_signal(isa);
+ else
+ v->signal = (v->rxsubchans & V4L2_TUNER_SUB_STEREO) ?
+ 0xffff : 0;
+ return 0;
+}
+
+static int radio_isa_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ struct radio_isa_card *isa = video_drvdata(file);
+ const struct radio_isa_ops *ops = isa->drv->ops;
+
+ if (v->index)
+ return -EINVAL;
+ if (ops->s_stereo) {
+ isa->stereo = (v->audmode == V4L2_TUNER_MODE_STEREO);
+ return ops->s_stereo(isa, isa->stereo);
+ }
+ return 0;
+}
+
+static int radio_isa_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct radio_isa_card *isa = video_drvdata(file);
+ int res;
+
+ if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+ return -EINVAL;
+ f->frequency = clamp(f->frequency, FREQ_LOW, FREQ_HIGH);
+ res = isa->drv->ops->s_frequency(isa, f->frequency);
+ if (res == 0)
+ isa->freq = f->frequency;
+ return res;
+}
+
+static int radio_isa_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct radio_isa_card *isa = video_drvdata(file);
+
+ if (f->tuner != 0)
+ return -EINVAL;
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = isa->freq;
+ return 0;
+}
+
+static int radio_isa_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct radio_isa_card *isa =
+ container_of(ctrl->handler, struct radio_isa_card, hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ return isa->drv->ops->s_mute_volume(isa, ctrl->val,
+ isa->volume ? isa->volume->val : 0);
+ }
+ return -EINVAL;
+}
+
+static int radio_isa_log_status(struct file *file, void *priv)
+{
+ struct radio_isa_card *isa = video_drvdata(file);
+
+ v4l2_info(&isa->v4l2_dev, "I/O Port = 0x%03x\n", isa->io);
+ v4l2_ctrl_handler_log_status(&isa->hdl, isa->v4l2_dev.name);
+ return 0;
+}
+
+static int radio_isa_subscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ if (sub->type == V4L2_EVENT_CTRL)
+ return v4l2_event_subscribe(fh, sub, 0);
+ return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops radio_isa_ctrl_ops = {
+ .s_ctrl = radio_isa_s_ctrl,
+};
+
+static const struct v4l2_file_operations radio_isa_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_isa_ioctl_ops = {
+ .vidioc_querycap = radio_isa_querycap,
+ .vidioc_g_tuner = radio_isa_g_tuner,
+ .vidioc_s_tuner = radio_isa_s_tuner,
+ .vidioc_g_frequency = radio_isa_g_frequency,
+ .vidioc_s_frequency = radio_isa_s_frequency,
+ .vidioc_log_status = radio_isa_log_status,
+ .vidioc_subscribe_event = radio_isa_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+int radio_isa_match(struct device *pdev, unsigned int dev)
+{
+ struct radio_isa_driver *drv = pdev->platform_data;
+
+ return drv->probe || drv->io_params[dev] >= 0;
+}
+EXPORT_SYMBOL_GPL(radio_isa_match);
+
+static bool radio_isa_valid_io(const struct radio_isa_driver *drv, int io)
+{
+ int i;
+
+ for (i = 0; i < drv->num_of_io_ports; i++)
+ if (drv->io_ports[i] == io)
+ return true;
+ return false;
+}
+
+int radio_isa_probe(struct device *pdev, unsigned int dev)
+{
+ struct radio_isa_driver *drv = pdev->platform_data;
+ const struct radio_isa_ops *ops = drv->ops;
+ struct v4l2_device *v4l2_dev;
+ struct radio_isa_card *isa;
+ int res;
+
+ isa = drv->ops->alloc();
+ if (isa == NULL)
+ return -ENOMEM;
+ dev_set_drvdata(pdev, isa);
+ isa->drv = drv;
+ isa->io = drv->io_params[dev];
+ v4l2_dev = &isa->v4l2_dev;
+ strlcpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name));
+
+ if (drv->probe && ops->probe) {
+ int i;
+
+ for (i = 0; i < drv->num_of_io_ports; ++i) {
+ int io = drv->io_ports[i];
+
+ if (request_region(io, drv->region_size, v4l2_dev->name)) {
+ bool found = ops->probe(isa, io);
+
+ release_region(io, drv->region_size);
+ if (found) {
+ isa->io = io;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!radio_isa_valid_io(drv, isa->io)) {
+ int i;
+
+ if (isa->io < 0)
+ return -ENODEV;
+ v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x",
+ drv->io_ports[0]);
+ for (i = 1; i < drv->num_of_io_ports; i++)
+ printk(KERN_CONT "/0x%03x", drv->io_ports[i]);
+ printk(KERN_CONT ".\n");
+ kfree(isa);
+ return -EINVAL;
+ }
+
+ if (!request_region(isa->io, drv->region_size, v4l2_dev->name)) {
+ v4l2_err(v4l2_dev, "port 0x%x already in use\n", isa->io);
+ kfree(isa);
+ return -EBUSY;
+ }
+
+ res = v4l2_device_register(pdev, v4l2_dev);
+ if (res < 0) {
+ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+ goto err_dev_reg;
+ }
+
+ v4l2_ctrl_handler_init(&isa->hdl, 1);
+ isa->mute = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ if (drv->max_volume)
+ isa->volume = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, drv->max_volume, 1,
+ drv->max_volume);
+ v4l2_dev->ctrl_handler = &isa->hdl;
+ if (isa->hdl.error) {
+ res = isa->hdl.error;
+ v4l2_err(v4l2_dev, "Could not register controls\n");
+ goto err_hdl;
+ }
+ if (drv->max_volume)
+ v4l2_ctrl_cluster(2, &isa->mute);
+ v4l2_dev->ctrl_handler = &isa->hdl;
+
+ mutex_init(&isa->lock);
+ isa->vdev.lock = &isa->lock;
+ strlcpy(isa->vdev.name, v4l2_dev->name, sizeof(isa->vdev.name));
+ isa->vdev.v4l2_dev = v4l2_dev;
+ isa->vdev.fops = &radio_isa_fops;
+ isa->vdev.ioctl_ops = &radio_isa_ioctl_ops;
+ isa->vdev.release = video_device_release_empty;
+ set_bit(V4L2_FL_USE_FH_PRIO, &isa->vdev.flags);
+ video_set_drvdata(&isa->vdev, isa);
+ isa->freq = FREQ_LOW;
+ isa->stereo = drv->has_stereo;
+
+ if (ops->init)
+ res = ops->init(isa);
+ if (!res)
+ res = v4l2_ctrl_handler_setup(&isa->hdl);
+ if (!res)
+ res = ops->s_frequency(isa, isa->freq);
+ if (!res && ops->s_stereo)
+ res = ops->s_stereo(isa, isa->stereo);
+ if (res < 0) {
+ v4l2_err(v4l2_dev, "Could not setup card\n");
+ goto err_node_reg;
+ }
+ res = video_register_device(&isa->vdev, VFL_TYPE_RADIO,
+ drv->radio_nr_params[dev]);
+ if (res < 0) {
+ v4l2_err(v4l2_dev, "Could not register device node\n");
+ goto err_node_reg;
+ }
+
+ v4l2_info(v4l2_dev, "Initialized radio card %s on port 0x%03x\n",
+ drv->card, isa->io);
+ return 0;
+
+err_node_reg:
+ v4l2_ctrl_handler_free(&isa->hdl);
+err_hdl:
+ v4l2_device_unregister(&isa->v4l2_dev);
+err_dev_reg:
+ release_region(isa->io, drv->region_size);
+ kfree(isa);
+ return res;
+}
+EXPORT_SYMBOL_GPL(radio_isa_probe);
+
+int radio_isa_remove(struct device *pdev, unsigned int dev)
+{
+ struct radio_isa_card *isa = dev_get_drvdata(pdev);
+ const struct radio_isa_ops *ops = isa->drv->ops;
+
+ ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0);
+ video_unregister_device(&isa->vdev);
+ v4l2_ctrl_handler_free(&isa->hdl);
+ v4l2_device_unregister(&isa->v4l2_dev);
+ release_region(isa->io, isa->drv->region_size);
+ v4l2_info(&isa->v4l2_dev, "Removed radio card %s\n", isa->drv->card);
+ kfree(isa);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(radio_isa_remove);
diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h
new file mode 100644
index 000000000000..8a0ea84d86de
--- /dev/null
+++ b/drivers/media/radio/radio-isa.h
@@ -0,0 +1,105 @@
+/*
+ * Framework for ISA radio drivers.
+ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers
+ * to concentrate on the actual hardware operation.
+ *
+ * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com>
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef _RADIO_ISA_H_
+#define _RADIO_ISA_H_
+
+#include <linux/isa.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+struct radio_isa_driver;
+struct radio_isa_ops;
+
+/* Core structure for radio ISA cards */
+struct radio_isa_card {
+ const struct radio_isa_driver *drv;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler hdl;
+ struct video_device vdev;
+ struct mutex lock;
+ const struct radio_isa_ops *ops;
+ struct { /* mute/volume cluster */
+ struct v4l2_ctrl *mute;
+ struct v4l2_ctrl *volume;
+ };
+ /* I/O port */
+ int io;
+
+ /* Card is in stereo audio mode */
+ bool stereo;
+ /* Current frequency */
+ u32 freq;
+};
+
+struct radio_isa_ops {
+ /* Allocate and initialize a radio_isa_card struct */
+ struct radio_isa_card *(*alloc)(void);
+ /* Probe whether a card is present at the given port */
+ bool (*probe)(struct radio_isa_card *isa, int io);
+ /* Special card initialization can be done here, this is called after
+ * the standard controls are registered, but before they are setup,
+ * thus allowing drivers to add their own controls here. */
+ int (*init)(struct radio_isa_card *isa);
+ /* Set mute and volume. */
+ int (*s_mute_volume)(struct radio_isa_card *isa, bool mute, int volume);
+ /* Set frequency */
+ int (*s_frequency)(struct radio_isa_card *isa, u32 freq);
+ /* Set stereo/mono audio mode */
+ int (*s_stereo)(struct radio_isa_card *isa, bool stereo);
+ /* Get rxsubchans value for VIDIOC_G_TUNER */
+ u32 (*g_rxsubchans)(struct radio_isa_card *isa);
+ /* Get the signal strength for VIDIOC_G_TUNER */
+ u32 (*g_signal)(struct radio_isa_card *isa);
+};
+
+/* Top level structure needed to instantiate the cards */
+struct radio_isa_driver {
+ struct isa_driver driver;
+ const struct radio_isa_ops *ops;
+ /* The module_param_array with the specified I/O ports */
+ int *io_params;
+ /* The module_param_array with the radio_nr values */
+ int *radio_nr_params;
+ /* Whether we should probe for possible cards */
+ bool probe;
+ /* The list of possible I/O ports */
+ const int *io_ports;
+ /* The size of that list */
+ int num_of_io_ports;
+ /* The region size to request */
+ unsigned region_size;
+ /* The name of the card */
+ const char *card;
+ /* Card can capture stereo audio */
+ bool has_stereo;
+ /* The maximum volume for the volume control. If 0, then there
+ is no volume control possible. */
+ int max_volume;
+};
+
+int radio_isa_match(struct device *pdev, unsigned int dev);
+int radio_isa_probe(struct device *pdev, unsigned int dev);
+int radio_isa_remove(struct device *pdev, unsigned int dev);
+
+#endif
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
new file mode 100644
index 000000000000..55bd1d2937c8
--- /dev/null
+++ b/drivers/media/radio/radio-keene.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2012 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+
+/* driver and module definitions */
+MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
+MODULE_DESCRIPTION("Keene FM Transmitter driver");
+MODULE_LICENSE("GPL");
+
+/* Actually, it advertises itself as a Logitech */
+#define USB_KEENE_VENDOR 0x046d
+#define USB_KEENE_PRODUCT 0x0a0e
+
+/* Probably USB_TIMEOUT should be modified in module parameter */
+#define BUFFER_LENGTH 8
+#define USB_TIMEOUT 500
+
+/* Frequency limits in MHz */
+#define FREQ_MIN 76U
+#define FREQ_MAX 108U
+#define FREQ_MUL 16000U
+
+/* USB Device ID List */
+static struct usb_device_id usb_keene_device_table[] = {
+ {USB_DEVICE_AND_INTERFACE_INFO(USB_KEENE_VENDOR, USB_KEENE_PRODUCT,
+ USB_CLASS_HID, 0, 0) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_keene_device_table);
+
+struct keene_device {
+ struct usb_device *usbdev;
+ struct usb_interface *intf;
+ struct video_device vdev;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler hdl;
+ struct mutex lock;
+
+ u8 *buffer;
+ unsigned curfreq;
+ u8 tx;
+ u8 pa;
+ bool stereo;
+ bool muted;
+ bool preemph_75_us;
+};
+
+static inline struct keene_device *to_keene_dev(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct keene_device, v4l2_dev);
+}
+
+/* Set frequency (if non-0), PA, mute and turn on/off the FM transmitter. */
+static int keene_cmd_main(struct keene_device *radio, unsigned freq, bool play)
+{
+ unsigned short freq_send = freq ? (freq - 76 * 16000) / 800 : 0;
+ int ret;
+
+ radio->buffer[0] = 0x00;
+ radio->buffer[1] = 0x50;
+ radio->buffer[2] = (freq_send >> 8) & 0xff;
+ radio->buffer[3] = freq_send & 0xff;
+ radio->buffer[4] = radio->pa;
+ /* If bit 4 is set, then tune to the frequency.
+ If bit 3 is set, then unmute; if bit 2 is set, then mute.
+ If bit 1 is set, then enter idle mode; if bit 0 is set,
+ then enter transit mode.
+ */
+ radio->buffer[5] = (radio->muted ? 4 : 8) | (play ? 1 : 2) |
+ (freq ? 0x10 : 0);
+ radio->buffer[6] = 0x00;
+ radio->buffer[7] = 0x00;
+
+ ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+ 9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
+
+ if (ret < 0) {
+ dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret);
+ return ret;
+ }
+ if (freq)
+ radio->curfreq = freq;
+ return 0;
+}
+
+/* Set TX, stereo and preemphasis mode (50 us vs 75 us). */
+static int keene_cmd_set(struct keene_device *radio)
+{
+ int ret;
+
+ radio->buffer[0] = 0x00;
+ radio->buffer[1] = 0x51;
+ radio->buffer[2] = radio->tx;
+ /* If bit 0 is set, then transmit mono, otherwise stereo.
+ If bit 2 is set, then enable 75 us preemphasis, otherwise
+ it is 50 us. */
+ radio->buffer[3] = (!radio->stereo) | (radio->preemph_75_us ? 4 : 0);
+ radio->buffer[4] = 0x00;
+ radio->buffer[5] = 0x00;
+ radio->buffer[6] = 0x00;
+ radio->buffer[7] = 0x00;
+
+ ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+ 9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
+
+ if (ret < 0) {
+ dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret);
+ return ret;
+ }
+ return 0;
+}
+
+/* Handle unplugging the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_keene_device_release.
+ */
+static void usb_keene_disconnect(struct usb_interface *intf)
+{
+ struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf));
+
+ v4l2_device_get(&radio->v4l2_dev);
+ mutex_lock(&radio->lock);
+ usb_set_intfdata(intf, NULL);
+ video_unregister_device(&radio->vdev);
+ v4l2_device_disconnect(&radio->v4l2_dev);
+ mutex_unlock(&radio->lock);
+ v4l2_device_put(&radio->v4l2_dev);
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+{
+ struct keene_device *radio = video_drvdata(file);
+
+ strlcpy(v->driver, "radio-keene", sizeof(v->driver));
+ strlcpy(v->card, "Keene FM Transmitter", sizeof(v->card));
+ usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
+ v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR;
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int vidioc_g_modulator(struct file *file, void *priv,
+ struct v4l2_modulator *v)
+{
+ struct keene_device *radio = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+ strlcpy(v->name, "FM", sizeof(v->name));
+ v->rangelow = FREQ_MIN * FREQ_MUL;
+ v->rangehigh = FREQ_MAX * FREQ_MUL;
+ v->txsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ return 0;
+}
+
+static int vidioc_s_modulator(struct file *file, void *priv,
+ struct v4l2_modulator *v)
+{
+ struct keene_device *radio = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+ radio->stereo = (v->txsubchans == V4L2_TUNER_SUB_STEREO);
+ return keene_cmd_set(radio);
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct keene_device *radio = video_drvdata(file);
+
+ if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+ return -EINVAL;
+ f->frequency = clamp(f->frequency,
+ FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
+ return keene_cmd_main(radio, f->frequency, true);
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct keene_device *radio = video_drvdata(file);
+
+ if (f->tuner != 0)
+ return -EINVAL;
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = radio->curfreq;
+ return 0;
+}
+
+static int keene_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ static const u8 db2tx[] = {
+ /* -15, -12, -9, -6, -3, 0 dB */
+ 0x03, 0x13, 0x02, 0x12, 0x22, 0x32,
+ /* 3, 6, 9, 12, 15, 18 dB */
+ 0x21, 0x31, 0x20, 0x30, 0x40, 0x50
+ };
+ struct keene_device *radio =
+ container_of(ctrl->handler, struct keene_device, hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ radio->muted = ctrl->val;
+ return keene_cmd_main(radio, 0, true);
+
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ /* To go from dBuV to the register value we apply the
+ following formula: */
+ radio->pa = (ctrl->val - 71) * 100 / 62;
+ return keene_cmd_main(radio, 0, true);
+
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ radio->preemph_75_us = ctrl->val == V4L2_PREEMPHASIS_75_uS;
+ return keene_cmd_set(radio);
+
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+ radio->tx = db2tx[(ctrl->val - ctrl->minimum) / ctrl->step];
+ return keene_cmd_set(radio);
+ }
+ return -EINVAL;
+}
+
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_CTRL:
+ return v4l2_event_subscribe(fh, sub, 0);
+ default:
+ return -EINVAL;
+ }
+}
+
+
+/* File system interface */
+static const struct v4l2_file_operations usb_keene_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ctrl_ops keene_ctrl_ops = {
+ .s_ctrl = keene_s_ctrl,
+};
+
+static const struct v4l2_ioctl_ops usb_keene_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_modulator = vidioc_g_modulator,
+ .vidioc_s_modulator = vidioc_s_modulator,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = vidioc_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static void usb_keene_video_device_release(struct v4l2_device *v4l2_dev)
+{
+ struct keene_device *radio = to_keene_dev(v4l2_dev);
+
+ /* free rest memory */
+ v4l2_ctrl_handler_free(&radio->hdl);
+ kfree(radio->buffer);
+ kfree(radio);
+}
+
+/* check if the device is present and register with v4l and usb if it is */
+static int usb_keene_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct keene_device *radio;
+ struct v4l2_ctrl_handler *hdl;
+ int retval = 0;
+
+ /*
+ * The Keene FM transmitter USB device has the same USB ID as
+ * the Logitech AudioHub Speaker, but it should ignore the hid.
+ * Check if the name is that of the Keene device.
+ * If not, then someone connected the AudioHub and we shouldn't
+ * attempt to handle this driver.
+ * For reference: the product name of the AudioHub is
+ * "AudioHub Speaker".
+ */
+ if (dev->product && strcmp(dev->product, "B-LINK USB Audio "))
+ return -ENODEV;
+
+ radio = kzalloc(sizeof(struct keene_device), GFP_KERNEL);
+ if (radio)
+ radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+
+ if (!radio || !radio->buffer) {
+ dev_err(&intf->dev, "kmalloc for keene_device failed\n");
+ kfree(radio);
+ retval = -ENOMEM;
+ goto err;
+ }
+
+ hdl = &radio->hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_MUTE,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std_menu(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS,
+ V4L2_PREEMPHASIS_75_uS, 1, V4L2_PREEMPHASIS_50_uS);
+ v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_POWER_LEVEL,
+ 84, 118, 1, 118);
+ v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_COMPRESSION_GAIN,
+ -15, 18, 3, 0);
+ radio->pa = 118;
+ radio->tx = 0x32;
+ radio->stereo = true;
+ radio->curfreq = 95.16 * FREQ_MUL;
+ if (hdl->error) {
+ retval = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ goto err_v4l2;
+ }
+ retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
+ if (retval < 0) {
+ dev_err(&intf->dev, "couldn't register v4l2_device\n");
+ goto err_v4l2;
+ }
+
+ mutex_init(&radio->lock);
+
+ radio->v4l2_dev.ctrl_handler = hdl;
+ radio->v4l2_dev.release = usb_keene_video_device_release;
+ strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+ sizeof(radio->vdev.name));
+ radio->vdev.v4l2_dev = &radio->v4l2_dev;
+ radio->vdev.fops = &usb_keene_fops;
+ radio->vdev.ioctl_ops = &usb_keene_ioctl_ops;
+ radio->vdev.lock = &radio->lock;
+ radio->vdev.release = video_device_release_empty;
+
+ radio->usbdev = interface_to_usbdev(intf);
+ radio->intf = intf;
+ usb_set_intfdata(intf, &radio->v4l2_dev);
+
+ video_set_drvdata(&radio->vdev, radio);
+ set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
+
+ retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
+ if (retval < 0) {
+ dev_err(&intf->dev, "could not register video device\n");
+ goto err_vdev;
+ }
+ v4l2_ctrl_handler_setup(hdl);
+ dev_info(&intf->dev, "V4L2 device registered as %s\n",
+ video_device_node_name(&radio->vdev));
+ return 0;
+
+err_vdev:
+ v4l2_device_unregister(&radio->v4l2_dev);
+err_v4l2:
+ kfree(radio->buffer);
+ kfree(radio);
+err:
+ return retval;
+}
+
+/* USB subsystem interface */
+static struct usb_driver usb_keene_driver = {
+ .name = "radio-keene",
+ .probe = usb_keene_probe,
+ .disconnect = usb_keene_disconnect,
+ .id_table = usb_keene_device_table,
+};
+
+static int __init keene_init(void)
+{
+ int retval = usb_register(&usb_keene_driver);
+
+ if (retval)
+ pr_err(KBUILD_MODNAME
+ ": usb_register failed. Error number %d\n", retval);
+
+ return retval;
+}
+
+static void __exit keene_exit(void)
+{
+ usb_deregister(&usb_keene_driver);
+}
+
+module_init(keene_init);
+module_exit(keene_exit);
+
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index f872a54cf3d9..740a3d5520c7 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -42,67 +42,37 @@
#include <linux/videodev2.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <sound/tea575x-tuner.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-
-#define DRIVER_VERSION "0.7.8"
-
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
-MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
+MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000.");
MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
+MODULE_VERSION("1.0.0");
static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-#define dprintk(dev, num, fmt, arg...) \
- v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg)
-
-#ifndef PCI_VENDOR_ID_GUILLEMOT
-#define PCI_VENDOR_ID_GUILLEMOT 0x5046
-#endif
-
-#ifndef PCI_DEVICE_ID_GUILLEMOT
-#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001
-#endif
-
+module_param(radio_nr, int, 0644);
+MODULE_PARM_DESC(radio_nr, "Radio device number");
/* TEA5757 pin mappings */
static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16;
-#define FREQ_LO (87 * 16000)
-#define FREQ_HI (108 * 16000)
-
-#define FREQ_IF 171200 /* 10.7*16000 */
-#define FREQ_STEP 200 /* 12.5*16 */
-
-/* (x==fmhz*16*1000) -> bits */
-#define FREQ2BITS(x) \
- ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2)
-
-#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
+static atomic_t maxiradio_instance = ATOMIC_INIT(0);
+#define PCI_VENDOR_ID_GUILLEMOT 0x5046
+#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001
struct maxiradio
{
+ struct snd_tea575x tea;
struct v4l2_device v4l2_dev;
- struct video_device vdev;
struct pci_dev *pdev;
u16 io; /* base of radio io */
- u16 muted; /* VIDEO_AUDIO_MUTE */
- u16 stereo; /* VIDEO_TUNER_STEREO_ON */
- u16 tuned; /* signal strength (0 or 0xffff) */
-
- unsigned long freq;
-
- struct mutex lock;
};
static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev)
@@ -110,259 +80,41 @@ static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev)
return container_of(v4l2_dev, struct maxiradio, v4l2_dev);
}
-static void outbit(unsigned long bit, u16 io)
-{
- int val = power | wren | (bit ? data : 0);
-
- outb(val, io);
- udelay(4);
- outb(val | clk, io);
- udelay(4);
- outb(val, io);
- udelay(4);
-}
-
-static void turn_power(struct maxiradio *dev, int p)
-{
- if (p != 0) {
- dprintk(dev, 1, "Radio powered on\n");
- outb(power, dev->io);
- } else {
- dprintk(dev, 1, "Radio powered off\n");
- outb(0, dev->io);
- }
-}
-
-static void set_freq(struct maxiradio *dev, u32 freq)
-{
- unsigned long int si;
- int bl;
- int io = dev->io;
- int val = FREQ2BITS(freq);
-
- /* TEA5757 shift register bits (see pdf) */
-
- outbit(0, io); /* 24 search */
- outbit(1, io); /* 23 search up/down */
-
- outbit(0, io); /* 22 stereo/mono */
-
- outbit(0, io); /* 21 band */
- outbit(0, io); /* 20 band (only 00=FM works I think) */
-
- outbit(0, io); /* 19 port ? */
- outbit(0, io); /* 18 port ? */
-
- outbit(0, io); /* 17 search level */
- outbit(0, io); /* 16 search level */
-
- si = 0x8000;
- for (bl = 1; bl <= 16; bl++) {
- outbit(val & si, io);
- si >>= 1;
- }
-
- dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n",
- freq / 16000,
- freq % 16000 * 100 / 16000);
-
- turn_power(dev, 1);
-}
-
-static int get_stereo(u16 io)
+static void maxiradio_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
{
- outb(power,io);
- udelay(4);
+ struct maxiradio *dev = tea->private_data;
+ u8 bits = 0;
- return !(inb(io) & mo_st);
-}
+ bits |= (pins & TEA575X_DATA) ? data : 0;
+ bits |= (pins & TEA575X_CLK) ? clk : 0;
+ bits |= (pins & TEA575X_WREN) ? wren : 0;
+ bits |= power;
-static int get_tune(u16 io)
-{
- outb(power+clk,io);
- udelay(4);
-
- return !(inb(io) & mo_st);
-}
-
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- struct maxiradio *dev = video_drvdata(file);
-
- strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver));
- strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card));
- snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- return 0;
+ outb(bits, dev->io);
}
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+/* Note: this card cannot read out the data of the shift registers,
+ only the mono/stereo pin works. */
+static u8 maxiradio_tea575x_get_pins(struct snd_tea575x *tea)
{
- struct maxiradio *dev = video_drvdata(file);
-
- if (v->index > 0)
- return -EINVAL;
-
- mutex_lock(&dev->lock);
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = FREQ_LO;
- v->rangehigh = FREQ_HI;
- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- v->capability = V4L2_TUNER_CAP_LOW;
- if (get_stereo(dev->io))
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xffff * get_tune(dev->io);
- mutex_unlock(&dev->lock);
+ struct maxiradio *dev = tea->private_data;
+ u8 bits = inb(dev->io);
- return 0;
+ return ((bits & data) ? TEA575X_DATA : 0) |
+ ((bits & mo_st) ? TEA575X_MOST : 0);
}
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+static void maxiradio_tea575x_set_direction(struct snd_tea575x *tea, bool output)
{
- return v->index ? -EINVAL : 0;
}
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct maxiradio *dev = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
- dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
- f->frequency / 16000,
- f->frequency % 16000 * 100 / 16000,
- FREQ_LO / 16000, FREQ_HI / 16000);
-
- return -EINVAL;
- }
-
- mutex_lock(&dev->lock);
- dev->freq = f->frequency;
- set_freq(dev, dev->freq);
- msleep(125);
- mutex_unlock(&dev->lock);
-
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct maxiradio *dev = video_drvdata(file);
-
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = dev->freq;
-
- dprintk(dev, 4, "radio freq is %d.%02d MHz",
- f->frequency / 16000,
- f->frequency % 16000 * 100 / 16000);
-
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct maxiradio *dev = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = dev->muted;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct maxiradio *dev = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- mutex_lock(&dev->lock);
- dev->muted = ctrl->value;
- if (dev->muted)
- turn_power(dev, 0);
- else
- set_freq(dev, dev->freq);
- mutex_unlock(&dev->lock);
- return 0;
- }
-
- return -EINVAL;
-}
-
-static const struct v4l2_file_operations maxiradio_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
+static struct snd_tea575x_ops maxiradio_tea_ops = {
+ .set_pins = maxiradio_tea575x_set_pins,
+ .get_pins = maxiradio_tea575x_get_pins,
+ .set_direction = maxiradio_tea575x_set_direction,
};
-static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
-};
-
-static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit maxiradio_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct maxiradio *dev;
struct v4l2_device *v4l2_dev;
@@ -375,63 +127,60 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
}
v4l2_dev = &dev->v4l2_dev;
- mutex_init(&dev->lock);
- dev->pdev = pdev;
- dev->muted = 1;
- dev->freq = FREQ_LO;
-
- strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name));
+ v4l2_device_set_name(v4l2_dev, "maxiradio", &maxiradio_instance);
retval = v4l2_device_register(&pdev->dev, v4l2_dev);
if (retval < 0) {
v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
goto errfr;
}
+ dev->tea.private_data = dev;
+ dev->tea.ops = &maxiradio_tea_ops;
+ /* The data pin cannot be read. This may be a hardware limitation, or
+ we just don't know how to read it. */
+ dev->tea.cannot_read_data = true;
+ dev->tea.v4l2_dev = v4l2_dev;
+ dev->tea.radio_nr = radio_nr;
+ strlcpy(dev->tea.card, "Maxi Radio FM2000", sizeof(dev->tea.card));
+ snprintf(dev->tea.bus_info, sizeof(dev->tea.bus_info),
+ "PCI:%s", pci_name(pdev));
+
+ retval = -ENODEV;
if (!request_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
- v4l2_err(v4l2_dev, "can't reserve I/O ports\n");
- goto err_out;
+ pci_resource_len(pdev, 0), v4l2_dev->name)) {
+ dev_err(&pdev->dev, "can't reserve I/O ports\n");
+ goto err_hdl;
}
if (pci_enable_device(pdev))
goto err_out_free_region;
dev->io = pci_resource_start(pdev, 0);
- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
- dev->vdev.v4l2_dev = v4l2_dev;
- dev->vdev.fops = &maxiradio_fops;
- dev->vdev.ioctl_ops = &maxiradio_ioctl_ops;
- dev->vdev.release = video_device_release_empty;
- video_set_drvdata(&dev->vdev, dev);
-
- if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_err(v4l2_dev, "can't register device!");
+ if (snd_tea575x_init(&dev->tea)) {
+ printk(KERN_ERR "radio-maxiradio: Unable to detect TEA575x tuner\n");
goto err_out_free_region;
}
-
- v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
-
- v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n",
- dev->io);
return 0;
err_out_free_region:
release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
-err_out:
+err_hdl:
v4l2_device_unregister(v4l2_dev);
errfr:
kfree(dev);
- return -ENODEV;
+ return retval;
}
-static void __devexit maxiradio_remove_one(struct pci_dev *pdev)
+static void __devexit maxiradio_remove(struct pci_dev *pdev)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
struct maxiradio *dev = to_maxiradio(v4l2_dev);
- video_unregister_device(&dev->vdev);
- v4l2_device_unregister(&dev->v4l2_dev);
+ snd_tea575x_exit(&dev->tea);
+ /* Turn off power */
+ outb(0, dev->io);
+ v4l2_device_unregister(v4l2_dev);
release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
}
@@ -446,19 +195,19 @@ MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl);
static struct pci_driver maxiradio_driver = {
.name = "radio-maxiradio",
.id_table = maxiradio_pci_tbl,
- .probe = maxiradio_init_one,
- .remove = __devexit_p(maxiradio_remove_one),
+ .probe = maxiradio_probe,
+ .remove = __devexit_p(maxiradio_remove),
};
-static int __init maxiradio_radio_init(void)
+static int __init maxiradio_init(void)
{
return pci_register_driver(&maxiradio_driver);
}
-static void __exit maxiradio_radio_exit(void)
+static void __exit maxiradio_exit(void)
{
pci_unregister_driver(&maxiradio_driver);
}
-module_init(maxiradio_radio_init);
-module_exit(maxiradio_radio_exit);
+module_init(maxiradio_init);
+module_exit(maxiradio_exit);
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index 3fb76e3834c9..87c1ee13b058 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -23,7 +23,7 @@ static int radio_nr = -1;
module_param(radio_nr, int, 0);
MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");
-static int mono;
+static bool mono;
module_param(mono, bool, 0);
MODULE_PARM_DESC(mono, "Force tuner into mono mode.");
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 3628be617ee9..b275c5d0fe9a 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -1,11 +1,12 @@
-/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
+/*
+ * RadioTrack II driver
+ * Copyright 1998 Ben Pfaff
*
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
*
- * TODO: Allow for more than one of these foolish entities :-)
- *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
@@ -18,323 +19,120 @@
#include <linux/io.h> /* outb, outb_p */
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
MODULE_AUTHOR("Ben Pfaff");
MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("0.1.99");
#ifndef CONFIG_RADIO_RTRACK2_PORT
#define CONFIG_RADIO_RTRACK2_PORT -1
#endif
-static int io = CONFIG_RADIO_RTRACK2_PORT;
-static int radio_nr = -1;
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
-module_param(radio_nr, int, 0);
-
-struct rtrack2
-{
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- int io;
- unsigned long curfreq;
- int muted;
- struct mutex lock;
-};
+#define RTRACK2_MAX 2
-static struct rtrack2 rtrack2_card;
+static int io[RTRACK2_MAX] = { [0] = CONFIG_RADIO_RTRACK2_PORT,
+ [1 ... (RTRACK2_MAX - 1)] = -1 };
+static int radio_nr[RTRACK2_MAX] = { [0 ... (RTRACK2_MAX - 1)] = -1 };
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
-/* local things */
-
-static void rt_mute(struct rtrack2 *dev)
-{
- if (dev->muted)
- return;
- mutex_lock(&dev->lock);
- outb(1, dev->io);
- mutex_unlock(&dev->lock);
- dev->muted = 1;
-}
-
-static void rt_unmute(struct rtrack2 *dev)
+static struct radio_isa_card *rtrack2_alloc(void)
{
- if(dev->muted == 0)
- return;
- mutex_lock(&dev->lock);
- outb(0, dev->io);
- mutex_unlock(&dev->lock);
- dev->muted = 0;
+ return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL);
}
-static void zero(struct rtrack2 *dev)
+static void zero(struct radio_isa_card *isa)
{
- outb_p(1, dev->io);
- outb_p(3, dev->io);
- outb_p(1, dev->io);
+ outb_p(1, isa->io);
+ outb_p(3, isa->io);
+ outb_p(1, isa->io);
}
-static void one(struct rtrack2 *dev)
+static void one(struct radio_isa_card *isa)
{
- outb_p(5, dev->io);
- outb_p(7, dev->io);
- outb_p(5, dev->io);
+ outb_p(5, isa->io);
+ outb_p(7, isa->io);
+ outb_p(5, isa->io);
}
-static int rt_setfreq(struct rtrack2 *dev, unsigned long freq)
+static int rtrack2_s_frequency(struct radio_isa_card *isa, u32 freq)
{
int i;
- mutex_lock(&dev->lock);
- dev->curfreq = freq;
freq = freq / 200 + 856;
- outb_p(0xc8, dev->io);
- outb_p(0xc9, dev->io);
- outb_p(0xc9, dev->io);
+ outb_p(0xc8, isa->io);
+ outb_p(0xc9, isa->io);
+ outb_p(0xc9, isa->io);
for (i = 0; i < 10; i++)
- zero(dev);
+ zero(isa);
for (i = 14; i >= 0; i--)
if (freq & (1 << i))
- one(dev);
+ one(isa);
else
- zero(dev);
-
- outb_p(0xc8, dev->io);
- if (!dev->muted)
- outb_p(0, dev->io);
-
- mutex_unlock(&dev->lock);
- return 0;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver));
- strlcpy(v->card, "RadioTrack II", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- return 0;
-}
+ zero(isa);
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- return v->index ? -EINVAL : 0;
-}
-
-static int rt_getsigstr(struct rtrack2 *dev)
-{
- int sig = 1;
-
- mutex_lock(&dev->lock);
- if (inb(dev->io) & 2) /* bit set = no signal present */
- sig = 0;
- mutex_unlock(&dev->lock);
- return sig;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- struct rtrack2 *rt = video_drvdata(file);
-
- if (v->index > 0)
- return -EINVAL;
-
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = 88 * 16000;
- v->rangehigh = 108 * 16000;
- v->rxsubchans = V4L2_TUNER_SUB_MONO;
- v->capability = V4L2_TUNER_CAP_LOW;
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xFFFF * rt_getsigstr(rt);
+ outb_p(0xc8, isa->io);
+ if (!v4l2_ctrl_g_ctrl(isa->mute))
+ outb_p(0, isa->io);
return 0;
}
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+static u32 rtrack2_g_signal(struct radio_isa_card *isa)
{
- struct rtrack2 *rt = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- rt_setfreq(rt, f->frequency);
- return 0;
+ /* bit set = no signal present */
+ return (inb(isa->io) & 2) ? 0 : 0xffff;
}
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+static int rtrack2_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
{
- struct rtrack2 *rt = video_drvdata(file);
-
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = rt->curfreq;
+ outb(mute, isa->io);
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct rtrack2 *rt = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = rt->muted;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- if (rt->muted)
- ctrl->value = 0;
- else
- ctrl->value = 65535;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct rtrack2 *rt = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- rt_mute(rt);
- else
- rt_unmute(rt);
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- if (ctrl->value)
- rt_unmute(rt);
- else
- rt_mute(rt);
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations rtrack2_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops rtrack2_ops = {
+ .alloc = rtrack2_alloc,
+ .s_mute_volume = rtrack2_s_mute_volume,
+ .s_frequency = rtrack2_s_frequency,
+ .g_signal = rtrack2_g_signal,
};
-static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+static const int rtrack2_ioports[] = { 0x20f, 0x30f };
+
+static struct radio_isa_driver rtrack2_driver = {
+ .driver = {
+ .match = radio_isa_match,
+ .probe = radio_isa_probe,
+ .remove = radio_isa_remove,
+ .driver = {
+ .name = "radio-rtrack2",
+ },
+ },
+ .io_params = io,
+ .radio_nr_params = radio_nr,
+ .io_ports = rtrack2_ioports,
+ .num_of_io_ports = ARRAY_SIZE(rtrack2_ioports),
+ .region_size = 4,
+ .card = "AIMSlab RadioTrack II",
+ .ops = &rtrack2_ops,
+ .has_stereo = true,
};
static int __init rtrack2_init(void)
{
- struct rtrack2 *dev = &rtrack2_card;
- struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
- int res;
-
- strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name));
- dev->io = io;
- if (dev->io == -1) {
- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n");
- return -EINVAL;
- }
- if (!request_region(dev->io, 4, "rtrack2")) {
- v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io);
- return -EBUSY;
- }
-
- res = v4l2_device_register(NULL, v4l2_dev);
- if (res < 0) {
- release_region(dev->io, 4);
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- return res;
- }
-
- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
- dev->vdev.v4l2_dev = v4l2_dev;
- dev->vdev.fops = &rtrack2_fops;
- dev->vdev.ioctl_ops = &rtrack2_ioctl_ops;
- dev->vdev.release = video_device_release_empty;
- video_set_drvdata(&dev->vdev, dev);
-
- /* mute card - prevents noisy bootups */
- outb(1, dev->io);
- dev->muted = 1;
-
- mutex_init(&dev->lock);
- if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(dev->io, 4);
- return -EINVAL;
- }
-
- v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
-
- return 0;
+ return isa_register_driver(&rtrack2_driver.driver, RTRACK2_MAX);
}
static void __exit rtrack2_exit(void)
{
- struct rtrack2 *dev = &rtrack2_card;
-
- video_unregister_device(&dev->vdev);
- v4l2_device_unregister(&dev->v4l2_dev);
- release_region(dev->io, 4);
+ isa_unregister_driver(&rtrack2_driver.driver);
}
module_init(rtrack2_init);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 2dd485996ba8..7c69214334bf 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -9,16 +9,23 @@
#include <linux/delay.h>
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
+#include <linux/slab.h>
#include <linux/ioport.h> /* request_region */
#include <linux/io.h> /* outb, outb_p */
+#include <linux/isa.h>
#include <sound/tea575x-tuner.h>
MODULE_AUTHOR("Ondrej Zary");
MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver");
MODULE_LICENSE("GPL");
+static int radio_nr = -1;
+module_param(radio_nr, int, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device number");
+
struct fmr2 {
int io;
+ struct v4l2_device v4l2_dev;
struct snd_tea575x tea;
struct v4l2_ctrl *volume;
struct v4l2_ctrl *balance;
@@ -26,7 +33,6 @@ struct fmr2 {
/* the port is hardwired so no need to support multiple cards */
#define FMR2_PORT 0x384
-static struct fmr2 fmr2_card;
/* TEA575x tuner pins */
#define STR_DATA (1 << 0)
@@ -172,7 +178,7 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea)
fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56);
fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0);
if (tea->ctrl_handler.error) {
- printk(KERN_ERR "radio-sf16fmr2: can't initialize contrls\n");
+ printk(KERN_ERR "radio-sf16fmr2: can't initialize controls\n");
return tea->ctrl_handler.error;
}
}
@@ -180,26 +186,46 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea)
return 0;
}
-static int __init fmr2_init(void)
+static int __devinit fmr2_probe(struct device *pdev, unsigned int dev)
{
- struct fmr2 *fmr2 = &fmr2_card;
+ struct fmr2 *fmr2;
+ int err;
+
+ fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
+ if (fmr2 == NULL)
+ return -ENOMEM;
+ strlcpy(fmr2->v4l2_dev.name, dev_name(pdev),
+ sizeof(fmr2->v4l2_dev.name));
fmr2->io = FMR2_PORT;
- if (!request_region(fmr2->io, 2, "SF16-FMR2")) {
+ if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) {
printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io);
+ kfree(fmr2);
return -EBUSY;
}
+ dev_set_drvdata(pdev, fmr2);
+ err = v4l2_device_register(pdev, &fmr2->v4l2_dev);
+ if (err < 0) {
+ v4l2_err(&fmr2->v4l2_dev, "Could not register v4l2_device\n");
+ release_region(fmr2->io, 2);
+ kfree(fmr2);
+ return err;
+ }
+ fmr2->tea.v4l2_dev = &fmr2->v4l2_dev;
fmr2->tea.private_data = fmr2;
+ fmr2->tea.radio_nr = radio_nr;
fmr2->tea.ops = &fmr2_tea_ops;
fmr2->tea.ext_init = fmr2_tea_ext_init;
strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card));
- strcpy(fmr2->tea.bus_info, "ISA");
+ snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "ISA:%s",
+ fmr2->v4l2_dev.name);
if (snd_tea575x_init(&fmr2->tea)) {
printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n");
release_region(fmr2->io, 2);
+ kfree(fmr2);
return -ENODEV;
}
@@ -207,12 +233,33 @@ static int __init fmr2_init(void)
return 0;
}
-static void __exit fmr2_exit(void)
+static int __exit fmr2_remove(struct device *pdev, unsigned int dev)
{
- struct fmr2 *fmr2 = &fmr2_card;
+ struct fmr2 *fmr2 = dev_get_drvdata(pdev);
snd_tea575x_exit(&fmr2->tea);
release_region(fmr2->io, 2);
+ v4l2_device_unregister(&fmr2->v4l2_dev);
+ kfree(fmr2);
+ return 0;
+}
+
+struct isa_driver fmr2_driver = {
+ .probe = fmr2_probe,
+ .remove = fmr2_remove,
+ .driver = {
+ .name = "radio-sf16fmr2",
+ },
+};
+
+static int __init fmr2_init(void)
+{
+ return isa_register_driver(&fmr2_driver, 1);
+}
+
+static void __exit fmr2_exit(void)
+{
+ isa_unregister_driver(&fmr2_driver);
}
module_init(fmr2_init);
diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
index d1fab5885061..c54210c7fef9 100644
--- a/drivers/media/radio/radio-si4713.c
+++ b/drivers/media/radio/radio-si4713.c
@@ -355,17 +355,4 @@ static struct platform_driver radio_si4713_pdriver = {
.remove = __exit_p(radio_si4713_pdriver_remove),
};
-/* Module Interface */
-static int __init radio_si4713_module_init(void)
-{
- return platform_driver_register(&radio_si4713_pdriver);
-}
-
-static void __exit radio_si4713_module_exit(void)
-{
- platform_driver_unregister(&radio_si4713_pdriver);
-}
-
-module_init(radio_si4713_module_init);
-module_exit(radio_si4713_module_exit);
-
+module_platform_driver(radio_si4713_pdriver);
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index db20904d01f0..6b1fae32b483 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -575,21 +575,7 @@ static struct i2c_driver tea5764_i2c_driver = {
.id_table = tea5764_id,
};
-/* init the driver */
-static int __init tea5764_init(void)
-{
- int ret = i2c_add_driver(&tea5764_i2c_driver);
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": "
- DRIVER_DESC "\n");
- return ret;
-}
-
-/* cleanup the driver */
-static void __exit tea5764_exit(void)
-{
- i2c_del_driver(&tea5764_i2c_driver);
-}
+module_i2c_driver(tea5764_i2c_driver);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -600,6 +586,3 @@ module_param(use_xtal, int, 0);
MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board");
module_param(radio_nr, int, 0);
MODULE_PARM_DESC(radio_nr, "video4linux device number to use");
-
-module_init(tea5764_init);
-module_exit(tea5764_exit);
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index f2ed9cc3cf3b..be10a802e3a9 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -16,11 +16,7 @@
* Frequency control is done digitally -- ie out(port,encodefreq(95.8));
* Volume Control is done digitally
*
- * there is a I2C controlled RDS decoder (SAA6588) onboard, which i would like to support someday
- * (as soon i have understand how to get started :)
- * If you can help me out with that, please contact me!!
- *
- *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
@@ -30,43 +26,24 @@
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/mutex.h>
#include <linux/io.h> /* outb, outb_p */
+#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
-MODULE_AUTHOR("R.OFFERMANNS & others");
+MODULE_AUTHOR("R. Offermans & others");
MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
-
-#ifndef CONFIG_RADIO_TERRATEC_PORT
-#define CONFIG_RADIO_TERRATEC_PORT 0x590
-#endif
+MODULE_VERSION("0.1.99");
-static int io = CONFIG_RADIO_TERRATEC_PORT;
+/* Note: there seems to be only one possible port (0x590), but without
+ hardware this is hard to verify. For now, this is the only one we will
+ support. */
+static int io = 0x590;
static int radio_nr = -1;
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
-module_param(radio_nr, int, 0);
-
-static struct v4l2_queryctrl radio_qctrl[] = {
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .default_value = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0xff,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }
-};
+module_param(radio_nr, int, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device number");
#define WRT_DIS 0x00
#define CLK_OFF 0x00
@@ -76,63 +53,24 @@ static struct v4l2_queryctrl radio_qctrl[] = {
#define CLK_ON 0x08
#define WRT_EN 0x10
-struct terratec
+static struct radio_isa_card *terratec_alloc(void)
{
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- int io;
- int curvol;
- unsigned long curfreq;
- int muted;
- struct mutex lock;
-};
-
-static struct terratec terratec_card;
-
-/* local things */
+ return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL);
+}
-static void tt_write_vol(struct terratec *tt, int volume)
+static int terratec_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
{
int i;
- volume = volume + (volume * 32); /* change both channels */
- mutex_lock(&tt->lock);
+ if (mute)
+ vol = 0;
+ vol = vol + (vol * 32); /* change both channels */
for (i = 0; i < 8; i++) {
- if (volume & (0x80 >> i))
- outb(0x80, tt->io + 1);
+ if (vol & (0x80 >> i))
+ outb(0x80, isa->io + 1);
else
- outb(0x00, tt->io + 1);
- }
- mutex_unlock(&tt->lock);
-}
-
-
-
-static void tt_mute(struct terratec *tt)
-{
- tt->muted = 1;
- tt_write_vol(tt, 0);
-}
-
-static int tt_setvol(struct terratec *tt, int vol)
-{
- if (vol == tt->curvol) { /* requested volume = current */
- if (tt->muted) { /* user is unmuting the card */
- tt->muted = 0;
- tt_write_vol(tt, vol); /* enable card */
- }
- return 0;
- }
-
- if (vol == 0) { /* volume = 0 means mute the card */
- tt_write_vol(tt, 0); /* "turn off card" by setting vol to 0 */
- tt->curvol = vol; /* track the volume state! */
- return 0;
+ outb(0x00, isa->io + 1);
}
-
- tt->muted = 0;
- tt_write_vol(tt, vol);
- tt->curvol = vol;
return 0;
}
@@ -140,20 +78,15 @@ static int tt_setvol(struct terratec *tt, int vol)
/* this is the worst part in this driver */
/* many more or less strange things are going on here, but hey, it works :) */
-static int tt_setfreq(struct terratec *tt, unsigned long freq1)
+static int terratec_s_frequency(struct radio_isa_card *isa, u32 freq)
{
- int freq;
int i;
int p;
- int temp;
+ int temp;
long rest;
unsigned char buffer[25]; /* we have to bit shift 25 registers */
- mutex_lock(&tt->lock);
-
- tt->curfreq = freq1;
-
- freq = freq1 / 160; /* convert the freq. to a nice to handle value */
+ freq = freq / 160; /* convert the freq. to a nice to handle value */
memset(buffer, 0, sizeof(buffer));
rest = freq * 10 + 10700; /* I once had understood what is going on here */
@@ -175,239 +108,61 @@ static int tt_setfreq(struct terratec *tt, unsigned long freq1)
for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */
if (buffer[i] == 1) {
- outb(WRT_EN | DATA, tt->io);
- outb(WRT_EN | DATA | CLK_ON, tt->io);
- outb(WRT_EN | DATA, tt->io);
+ outb(WRT_EN | DATA, isa->io);
+ outb(WRT_EN | DATA | CLK_ON, isa->io);
+ outb(WRT_EN | DATA, isa->io);
} else {
- outb(WRT_EN | 0x00, tt->io);
- outb(WRT_EN | 0x00 | CLK_ON, tt->io);
- }
- }
- outb(0x00, tt->io);
-
- mutex_unlock(&tt->lock);
-
- return 0;
-}
-
-static int tt_getsigstr(struct terratec *tt)
-{
- if (inb(tt->io) & 2) /* bit set = no signal present */
- return 0;
- return 1; /* signal present */
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- strlcpy(v->driver, "radio-terratec", sizeof(v->driver));
- strlcpy(v->card, "ActiveRadio", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- struct terratec *tt = video_drvdata(file);
-
- if (v->index > 0)
- return -EINVAL;
-
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = 87 * 16000;
- v->rangehigh = 108 * 16000;
- v->rxsubchans = V4L2_TUNER_SUB_MONO;
- v->capability = V4L2_TUNER_CAP_LOW;
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xFFFF * tt_getsigstr(tt);
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct terratec *tt = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- tt_setfreq(tt, f->frequency);
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct terratec *tt = video_drvdata(file);
-
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = tt->curfreq;
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
- if (qc->id && qc->id == radio_qctrl[i].id) {
- memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
- return 0;
+ outb(WRT_EN | 0x00, isa->io);
+ outb(WRT_EN | 0x00 | CLK_ON, isa->io);
}
}
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct terratec *tt = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (tt->muted)
- ctrl->value = 1;
- else
- ctrl->value = 0;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = tt->curvol * 6554;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct terratec *tt = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- tt_mute(tt);
- else
- tt_setvol(tt,tt->curvol);
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- tt_setvol(tt,ctrl->value);
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
+ outb(0x00, isa->io);
return 0;
}
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
+static u32 terratec_g_signal(struct radio_isa_card *isa)
{
- return a->index ? -EINVAL : 0;
+ /* bit set = no signal present */
+ return (inb(isa->io) & 2) ? 0 : 0xffff;
}
-static const struct v4l2_file_operations terratec_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops terratec_ops = {
+ .alloc = terratec_alloc,
+ .s_mute_volume = terratec_s_mute_volume,
+ .s_frequency = terratec_s_frequency,
+ .g_signal = terratec_g_signal,
};
-static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+static const int terratec_ioports[] = { 0x590 };
+
+static struct radio_isa_driver terratec_driver = {
+ .driver = {
+ .match = radio_isa_match,
+ .probe = radio_isa_probe,
+ .remove = radio_isa_remove,
+ .driver = {
+ .name = "radio-terratec",
+ },
+ },
+ .io_params = &io,
+ .radio_nr_params = &radio_nr,
+ .io_ports = terratec_ioports,
+ .num_of_io_ports = ARRAY_SIZE(terratec_ioports),
+ .region_size = 2,
+ .card = "TerraTec ActiveRadio",
+ .ops = &terratec_ops,
+ .has_stereo = true,
+ .max_volume = 10,
};
static int __init terratec_init(void)
{
- struct terratec *tt = &terratec_card;
- struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
- int res;
-
- strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name));
- tt->io = io;
- if (tt->io == -1) {
- v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n");
- return -EINVAL;
- }
- if (!request_region(tt->io, 2, "terratec")) {
- v4l2_err(v4l2_dev, "port 0x%x already in use\n", io);
- return -EBUSY;
- }
-
- res = v4l2_device_register(NULL, v4l2_dev);
- if (res < 0) {
- release_region(tt->io, 2);
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- return res;
- }
-
- strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name));
- tt->vdev.v4l2_dev = v4l2_dev;
- tt->vdev.fops = &terratec_fops;
- tt->vdev.ioctl_ops = &terratec_ioctl_ops;
- tt->vdev.release = video_device_release_empty;
- video_set_drvdata(&tt->vdev, tt);
-
- mutex_init(&tt->lock);
-
- /* mute card - prevents noisy bootups */
- tt_write_vol(tt, 0);
-
- if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(&tt->v4l2_dev);
- release_region(tt->io, 2);
- return -EINVAL;
- }
-
- v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
- return 0;
+ return isa_register_driver(&terratec_driver.driver, 1);
}
static void __exit terratec_exit(void)
{
- struct terratec *tt = &terratec_card;
- struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
-
- video_unregister_device(&tt->vdev);
- v4l2_device_unregister(&tt->v4l2_dev);
- release_region(tt->io, 2);
- v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n");
+ isa_unregister_driver(&terratec_driver.driver);
}
module_init(terratec_init);
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 3e9209f84e09..5d9a90ac3a1c 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -226,20 +226,7 @@ static struct platform_driver timbradio_platform_driver = {
.remove = timbradio_remove,
};
-/*--------------------------------------------------------------------------*/
-
-static int __init timbradio_init(void)
-{
- return platform_driver_register(&timbradio_platform_driver);
-}
-
-static void __exit timbradio_exit(void)
-{
- platform_driver_unregister(&timbradio_platform_driver);
-}
-
-module_init(timbradio_init);
-module_exit(timbradio_exit);
+module_platform_driver(timbradio_platform_driver);
MODULE_DESCRIPTION("Timberdale Radio driver");
MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index b3f45a019d82..26a8c6002121 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -21,13 +21,15 @@
#include <linux/ioport.h>
#include <linux/videodev2.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("0.1.99");
/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -35,39 +37,38 @@ MODULE_VERSION("0.0.3");
#define CONFIG_RADIO_TRUST_PORT -1
#endif
-static int io = CONFIG_RADIO_TRUST_PORT;
-static int radio_nr = -1;
+#define TRUST_MAX 2
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
-module_param(radio_nr, int, 0);
+static int io[TRUST_MAX] = { [0] = CONFIG_RADIO_TRUST_PORT,
+ [1 ... (TRUST_MAX - 1)] = -1 };
+static int radio_nr[TRUST_MAX] = { [0 ... (TRUST_MAX - 1)] = -1 };
+
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Trust FM Radio card (0x350 or 0x358)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
struct trust {
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- int io;
+ struct radio_isa_card isa;
int ioval;
- __u16 curvol;
- __u16 curbass;
- __u16 curtreble;
- int muted;
- unsigned long curfreq;
- int curstereo;
- int curmute;
- struct mutex lock;
};
-static struct trust trust_card;
+static struct radio_isa_card *trust_alloc(void)
+{
+ struct trust *tr = kzalloc(sizeof(*tr), GFP_KERNEL);
+
+ return tr ? &tr->isa : NULL;
+}
/* i2c addresses */
#define TDA7318_ADDR 0x88
#define TSA6060T_ADDR 0xc4
-#define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0)
-#define TR_SET_SCL outb(tr->ioval |= 2, tr->io)
-#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io)
-#define TR_SET_SDA outb(tr->ioval |= 1, tr->io)
-#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io)
+#define TR_DELAY do { inb(tr->isa.io); inb(tr->isa.io); inb(tr->isa.io); } while (0)
+#define TR_SET_SCL outb(tr->ioval |= 2, tr->isa.io)
+#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->isa.io)
+#define TR_SET_SDA outb(tr->ioval |= 1, tr->isa.io)
+#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->isa.io)
static void write_i2c(struct trust *tr, int n, ...)
{
@@ -84,10 +85,10 @@ static void write_i2c(struct trust *tr, int n, ...)
TR_CLR_SCL;
TR_DELAY;
- for(; n; n--) {
+ for (; n; n--) {
val = va_arg(args, unsigned);
- for(mask = 0x80; mask; mask >>= 1) {
- if(val & mask)
+ for (mask = 0x80; mask; mask >>= 1) {
+ if (val & mask)
TR_SET_SDA;
else
TR_CLR_SDA;
@@ -115,317 +116,128 @@ static void write_i2c(struct trust *tr, int n, ...)
va_end(args);
}
-static void tr_setvol(struct trust *tr, __u16 vol)
+static int trust_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
{
- mutex_lock(&tr->lock);
- tr->curvol = vol / 2048;
- write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f);
- mutex_unlock(&tr->lock);
-}
+ struct trust *tr = container_of(isa, struct trust, isa);
-static int basstreble2chip[15] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8
-};
-
-static void tr_setbass(struct trust *tr, __u16 bass)
-{
- mutex_lock(&tr->lock);
- tr->curbass = bass / 4370;
- write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]);
- mutex_unlock(&tr->lock);
-}
-
-static void tr_settreble(struct trust *tr, __u16 treble)
-{
- mutex_lock(&tr->lock);
- tr->curtreble = treble / 4370;
- write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]);
- mutex_unlock(&tr->lock);
+ tr->ioval = (tr->ioval & 0xf7) | (mute << 3);
+ outb(tr->ioval, isa->io);
+ write_i2c(tr, 2, TDA7318_ADDR, vol ^ 0x1f);
+ return 0;
}
-static void tr_setstereo(struct trust *tr, int stereo)
+static int trust_s_stereo(struct radio_isa_card *isa, bool stereo)
{
- mutex_lock(&tr->lock);
- tr->curstereo = !!stereo;
- tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2);
- outb(tr->ioval, tr->io);
- mutex_unlock(&tr->lock);
-}
+ struct trust *tr = container_of(isa, struct trust, isa);
-static void tr_setmute(struct trust *tr, int mute)
-{
- mutex_lock(&tr->lock);
- tr->curmute = !!mute;
- tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3);
- outb(tr->ioval, tr->io);
- mutex_unlock(&tr->lock);
+ tr->ioval = (tr->ioval & 0xfb) | (!stereo << 2);
+ outb(tr->ioval, isa->io);
+ return 0;
}
-static int tr_getsigstr(struct trust *tr)
+static u32 trust_g_signal(struct radio_isa_card *isa)
{
int i, v;
- mutex_lock(&tr->lock);
for (i = 0, v = 0; i < 100; i++)
- v |= inb(tr->io);
- mutex_unlock(&tr->lock);
+ v |= inb(isa->io);
return (v & 1) ? 0 : 0xffff;
}
-static int tr_getstereo(struct trust *tr)
-{
- /* don't know how to determine it, just return the setting */
- return tr->curstereo;
-}
-
-static void tr_setfreq(struct trust *tr, unsigned long f)
+static int trust_s_frequency(struct radio_isa_card *isa, u32 freq)
{
- mutex_lock(&tr->lock);
- tr->curfreq = f;
- f /= 160; /* Convert to 10 kHz units */
- f += 1070; /* Add 10.7 MHz IF */
- write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
- mutex_unlock(&tr->lock);
-}
+ struct trust *tr = container_of(isa, struct trust, isa);
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- strlcpy(v->driver, "radio-trust", sizeof(v->driver));
- strlcpy(v->card, "Trust FM Radio", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ freq /= 160; /* Convert to 10 kHz units */
+ freq += 1070; /* Add 10.7 MHz IF */
+ write_i2c(tr, 5, TSA6060T_ADDR, (freq << 1) | 1,
+ freq >> 7, 0x60 | ((freq >> 15) & 1), 0);
return 0;
}
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- struct trust *tr = video_drvdata(file);
-
- if (v->index > 0)
- return -EINVAL;
-
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = 87.5 * 16000;
- v->rangehigh = 108 * 16000;
- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- v->capability = V4L2_TUNER_CAP_LOW;
- if (tr_getstereo(tr))
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = tr_getsigstr(tr);
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- struct trust *tr = video_drvdata(file);
-
- if (v->index)
- return -EINVAL;
- tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO);
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct trust *tr = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- tr_setfreq(tr, f->frequency);
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct trust *tr = video_drvdata(file);
-
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = tr->curfreq;
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535);
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768);
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct trust *tr = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = tr->curmute;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = tr->curvol * 2048;
- return 0;
- case V4L2_CID_AUDIO_BASS:
- ctrl->value = tr->curbass * 4370;
- return 0;
- case V4L2_CID_AUDIO_TREBLE:
- ctrl->value = tr->curtreble * 4370;
- return 0;
- }
- return -EINVAL;
-}
+static int basstreble2chip[15] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8
+};
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int trust_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct trust *tr = video_drvdata(file);
+ struct radio_isa_card *isa =
+ container_of(ctrl->handler, struct radio_isa_card, hdl);
+ struct trust *tr = container_of(isa, struct trust, isa);
switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- tr_setmute(tr, ctrl->value);
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- tr_setvol(tr, ctrl->value);
- return 0;
case V4L2_CID_AUDIO_BASS:
- tr_setbass(tr, ctrl->value);
+ write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[ctrl->val]);
return 0;
case V4L2_CID_AUDIO_TREBLE:
- tr_settreble(tr, ctrl->value);
+ write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[ctrl->val]);
return 0;
}
return -EINVAL;
}
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations trust_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops trust_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+static const struct v4l2_ctrl_ops trust_ctrl_ops = {
+ .s_ctrl = trust_s_ctrl,
};
-static int __init trust_init(void)
+static int trust_initialize(struct radio_isa_card *isa)
{
- struct trust *tr = &trust_card;
- struct v4l2_device *v4l2_dev = &tr->v4l2_dev;
- int res;
+ struct trust *tr = container_of(isa, struct trust, isa);
- strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name));
- tr->io = io;
tr->ioval = 0xf;
- mutex_init(&tr->lock);
-
- if (tr->io == -1) {
- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n");
- return -EINVAL;
- }
- if (!request_region(tr->io, 2, "Trust FM Radio")) {
- v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io);
- return -EBUSY;
- }
-
- res = v4l2_device_register(NULL, v4l2_dev);
- if (res < 0) {
- release_region(tr->io, 2);
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- return res;
- }
-
- strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name));
- tr->vdev.v4l2_dev = v4l2_dev;
- tr->vdev.fops = &trust_fops;
- tr->vdev.ioctl_ops = &trust_ioctl_ops;
- tr->vdev.release = video_device_release_empty;
- video_set_drvdata(&tr->vdev, tr);
-
write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */
- tr_setvol(tr, 0xffff);
- tr_setbass(tr, 0x8000);
- tr_settreble(tr, 0x8000);
- tr_setstereo(tr, 1);
-
- /* mute card - prevents noisy bootups */
- tr_setmute(tr, 1);
+ v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops,
+ V4L2_CID_AUDIO_BASS, 0, 15, 1, 8);
+ v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops,
+ V4L2_CID_AUDIO_TREBLE, 0, 15, 1, 8);
+ return isa->hdl.error;
+}
- if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(tr->io, 2);
- return -EINVAL;
- }
+static const struct radio_isa_ops trust_ops = {
+ .init = trust_initialize,
+ .alloc = trust_alloc,
+ .s_mute_volume = trust_s_mute_volume,
+ .s_frequency = trust_s_frequency,
+ .s_stereo = trust_s_stereo,
+ .g_signal = trust_g_signal,
+};
- v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
+static const int trust_ioports[] = { 0x350, 0x358 };
+
+static struct radio_isa_driver trust_driver = {
+ .driver = {
+ .match = radio_isa_match,
+ .probe = radio_isa_probe,
+ .remove = radio_isa_remove,
+ .driver = {
+ .name = "radio-trust",
+ },
+ },
+ .io_params = io,
+ .radio_nr_params = radio_nr,
+ .io_ports = trust_ioports,
+ .num_of_io_ports = ARRAY_SIZE(trust_ioports),
+ .region_size = 2,
+ .card = "Trust FM Radio",
+ .ops = &trust_ops,
+ .has_stereo = true,
+ .max_volume = 31,
+};
- return 0;
+static int __init trust_init(void)
+{
+ return isa_register_driver(&trust_driver.driver, TRUST_MAX);
}
-static void __exit cleanup_trust_module(void)
+static void __exit trust_exit(void)
{
- struct trust *tr = &trust_card;
-
- video_unregister_device(&tr->vdev);
- v4l2_device_unregister(&tr->v4l2_dev);
- release_region(tr->io, 2);
+ isa_unregister_driver(&trust_driver.driver);
}
module_init(trust_init);
-module_exit(cleanup_trust_module);
+module_exit(trust_exit);
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 398726abc0c8..eb72a4d13758 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -33,63 +33,53 @@
#include <linux/ioport.h> /* request_region */
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/io.h> /* outb, outb_p */
+#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
#define DRIVER_VERSION "0.1.2"
MODULE_AUTHOR("Dr. Henrik Seidel");
MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
+MODULE_VERSION("0.1.99");
#ifndef CONFIG_RADIO_TYPHOON_PORT
#define CONFIG_RADIO_TYPHOON_PORT -1
#endif
#ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ
-#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0
+#define CONFIG_RADIO_TYPHOON_MUTEFREQ 87000
#endif
-static int io = CONFIG_RADIO_TYPHOON_PORT;
-static int radio_nr = -1;
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)");
-
-module_param(radio_nr, int, 0);
+#define TYPHOON_MAX 2
+static int io[TYPHOON_MAX] = { [0] = CONFIG_RADIO_TYPHOON_PORT,
+ [1 ... (TYPHOON_MAX - 1)] = -1 };
+static int radio_nr[TYPHOON_MAX] = { [0 ... (TYPHOON_MAX - 1)] = -1 };
static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ;
+
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Typhoon card (0x316 or 0x336)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
module_param(mutefreq, ulong, 0);
MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
-#define BANNER "Typhoon Radio Card driver v" DRIVER_VERSION "\n"
-
struct typhoon {
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- int io;
- int curvol;
+ struct radio_isa_card isa;
int muted;
- unsigned long curfreq;
- unsigned long mutefreq;
- struct mutex lock;
};
-static struct typhoon typhoon_card;
-
-static void typhoon_setvol_generic(struct typhoon *dev, int vol)
+static struct radio_isa_card *typhoon_alloc(void)
{
- mutex_lock(&dev->lock);
- vol >>= 14; /* Map 16 bit to 2 bit */
- vol &= 3;
- outb_p(vol / 2, dev->io); /* Set the volume, high bit. */
- outb_p(vol % 2, dev->io + 2); /* Set the volume, low bit. */
- mutex_unlock(&dev->lock);
+ struct typhoon *ty = kzalloc(sizeof(*ty), GFP_KERNEL);
+
+ return ty ? &ty->isa : NULL;
}
-static int typhoon_setfreq_generic(struct typhoon *dev,
- unsigned long frequency)
+static int typhoon_s_frequency(struct radio_isa_card *isa, u32 freq)
{
unsigned long outval;
unsigned long x;
@@ -105,302 +95,86 @@ static int typhoon_setfreq_generic(struct typhoon *dev,
*
*/
- mutex_lock(&dev->lock);
- x = frequency / 160;
+ x = freq / 160;
outval = (x * x + 2500) / 5000;
outval = (outval * x + 5000) / 10000;
outval -= (10 * x * x + 10433) / 20866;
outval += 4 * x - 11505;
- outb_p((outval >> 8) & 0x01, dev->io + 4);
- outb_p(outval >> 9, dev->io + 6);
- outb_p(outval & 0xff, dev->io + 8);
- mutex_unlock(&dev->lock);
-
- return 0;
-}
-
-static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency)
-{
- typhoon_setfreq_generic(dev, frequency);
- dev->curfreq = frequency;
- return 0;
-}
-
-static void typhoon_mute(struct typhoon *dev)
-{
- if (dev->muted == 1)
- return;
- typhoon_setvol_generic(dev, 0);
- typhoon_setfreq_generic(dev, dev->mutefreq);
- dev->muted = 1;
-}
-
-static void typhoon_unmute(struct typhoon *dev)
-{
- if (dev->muted == 0)
- return;
- typhoon_setfreq_generic(dev, dev->curfreq);
- typhoon_setvol_generic(dev, dev->curvol);
- dev->muted = 0;
-}
-
-static int typhoon_setvol(struct typhoon *dev, int vol)
-{
- if (dev->muted && vol != 0) { /* user is unmuting the card */
- dev->curvol = vol;
- typhoon_unmute(dev);
- return 0;
- }
- if (vol == dev->curvol) /* requested volume == current */
- return 0;
-
- if (vol == 0) { /* volume == 0 means mute the card */
- typhoon_mute(dev);
- dev->curvol = vol;
- return 0;
- }
- typhoon_setvol_generic(dev, vol);
- dev->curvol = vol;
- return 0;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- strlcpy(v->driver, "radio-typhoon", sizeof(v->driver));
- strlcpy(v->card, "Typhoon Radio", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- if (v->index > 0)
- return -EINVAL;
-
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = 87.5 * 16000;
- v->rangehigh = 108 * 16000;
- v->rxsubchans = V4L2_TUNER_SUB_MONO;
- v->capability = V4L2_TUNER_CAP_LOW;
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xFFFF; /* We can't get the signal strength */
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct typhoon *dev = video_drvdata(file);
-
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = dev->curfreq;
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct typhoon *dev = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- dev->curfreq = f->frequency;
- typhoon_setfreq(dev, dev->curfreq);
+ outb_p((outval >> 8) & 0x01, isa->io + 4);
+ outb_p(outval >> 9, isa->io + 6);
+ outb_p(outval & 0xff, isa->io + 8);
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
+static int typhoon_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535);
- }
- return -EINVAL;
-}
+ struct typhoon *ty = container_of(isa, struct typhoon, isa);
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct typhoon *dev = video_drvdata(file);
+ if (mute)
+ vol = 0;
+ vol >>= 14; /* Map 16 bit to 2 bit */
+ vol &= 3;
+ outb_p(vol / 2, isa->io); /* Set the volume, high bit. */
+ outb_p(vol % 2, isa->io + 2); /* Set the volume, low bit. */
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = dev->muted;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = dev->curvol;
- return 0;
+ if (vol == 0 && !ty->muted) {
+ ty->muted = true;
+ return typhoon_s_frequency(isa, mutefreq << 4);
}
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl (struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct typhoon *dev = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- typhoon_mute(dev);
- else
- typhoon_unmute(dev);
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- typhoon_setvol(dev, ctrl->value);
- return 0;
+ if (vol && ty->muted) {
+ ty->muted = false;
+ return typhoon_s_frequency(isa, isa->freq);
}
- return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
return 0;
}
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct typhoon *dev = video_drvdata(file);
- struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
-
- v4l2_info(v4l2_dev, BANNER);
-#ifdef MODULE
- v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n");
-#else
- v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n");
-#endif
- v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4);
- v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol);
- v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ? "on" : "off");
- v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io);
- v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4);
- return 0;
-}
-
-static const struct v4l2_file_operations typhoon_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops typhoon_ops = {
+ .alloc = typhoon_alloc,
+ .s_mute_volume = typhoon_s_mute_volume,
+ .s_frequency = typhoon_s_frequency,
};
-static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
- .vidioc_log_status = vidioc_log_status,
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
+static const int typhoon_ioports[] = { 0x316, 0x336 };
+
+static struct radio_isa_driver typhoon_driver = {
+ .driver = {
+ .match = radio_isa_match,
+ .probe = radio_isa_probe,
+ .remove = radio_isa_remove,
+ .driver = {
+ .name = "radio-typhoon",
+ },
+ },
+ .io_params = io,
+ .radio_nr_params = radio_nr,
+ .io_ports = typhoon_ioports,
+ .num_of_io_ports = ARRAY_SIZE(typhoon_ioports),
+ .region_size = 8,
+ .card = "Typhoon Radio",
+ .ops = &typhoon_ops,
+ .has_stereo = true,
+ .max_volume = 3,
};
static int __init typhoon_init(void)
{
- struct typhoon *dev = &typhoon_card;
- struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
- int res;
-
- strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name));
- dev->io = io;
-
- if (dev->io == -1) {
- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n");
- return -EINVAL;
- }
-
- if (mutefreq < 87000 || mutefreq > 108500) {
- v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n");
- v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
- return -EINVAL;
- }
- dev->curfreq = dev->mutefreq = mutefreq << 4;
-
- mutex_init(&dev->lock);
- if (!request_region(dev->io, 8, "typhoon")) {
- v4l2_err(v4l2_dev, "port 0x%x already in use\n",
- dev->io);
- return -EBUSY;
- }
-
- res = v4l2_device_register(NULL, v4l2_dev);
- if (res < 0) {
- release_region(dev->io, 8);
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- return res;
+ if (mutefreq < 87000 || mutefreq > 108000) {
+ printk(KERN_ERR "%s: You must set a frequency (in kHz) used when muting the card,\n",
+ typhoon_driver.driver.driver.name);
+ printk(KERN_ERR "%s: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108000)\n",
+ typhoon_driver.driver.driver.name);
+ return -ENODEV;
}
- v4l2_info(v4l2_dev, BANNER);
-
- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
- dev->vdev.v4l2_dev = v4l2_dev;
- dev->vdev.fops = &typhoon_fops;
- dev->vdev.ioctl_ops = &typhoon_ioctl_ops;
- dev->vdev.release = video_device_release_empty;
- video_set_drvdata(&dev->vdev, dev);
-
- /* mute card - prevents noisy bootups */
- typhoon_mute(dev);
-
- if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(&dev->v4l2_dev);
- release_region(dev->io, 8);
- return -EINVAL;
- }
- v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io);
- v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq);
-
- return 0;
+ return isa_register_driver(&typhoon_driver.driver, TYPHOON_MAX);
}
static void __exit typhoon_exit(void)
{
- struct typhoon *dev = &typhoon_card;
-
- video_unregister_device(&dev->vdev);
- v4l2_device_unregister(&dev->v4l2_dev);
- release_region(dev->io, 8);
+ isa_unregister_driver(&typhoon_driver.driver);
}
+
module_init(typhoon_init);
module_exit(typhoon_exit);
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index 8aa4968d57bc..f1b607099b6c 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -2148,8 +2148,6 @@ pdata_err:
return r;
}
-MODULE_ALIAS("platform:wl1273_fm_radio");
-
static struct platform_driver wl1273_fm_radio_driver = {
.probe = wl1273_fm_radio_probe,
.remove = __devexit_p(wl1273_fm_radio_remove),
@@ -2159,20 +2157,9 @@ static struct platform_driver wl1273_fm_radio_driver = {
},
};
-static int __init wl1273_fm_module_init(void)
-{
- pr_info("%s\n", __func__);
- return platform_driver_register(&wl1273_fm_radio_driver);
-}
-module_init(wl1273_fm_module_init);
-
-static void __exit wl1273_fm_module_exit(void)
-{
- platform_driver_unregister(&wl1273_fm_radio_driver);
- pr_info(DRIVER_DESC ", Exiting.\n");
-}
-module_exit(wl1273_fm_module_exit);
+module_platform_driver(wl1273_fm_radio_driver);
MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wl1273_fm_radio");
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index f5613b948203..026e88eef29c 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -1,5 +1,6 @@
-/* zoltrix radio plus driver for Linux radio support
- * (c) 1998 C. van Schaik <carl@leg.uct.ac.za>
+/*
+ * Zoltrix Radio Plus driver
+ * Copyright 1998 C. van Schaik <carl@leg.uct.ac.za>
*
* BUGS
* Due to the inconsistency in reading from the signal flags
@@ -27,6 +28,14 @@
*
* 2006-07-24 - Converted to V4L2 API
* by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
+ *
+ * Note that this is the driver for the Zoltrix Radio Plus.
+ * This driver does not work for the Zoltrix Radio Plus 108 or the
+ * Zoltrix Radio Plus for Windows.
+ *
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
*/
#include <linux/module.h> /* Modules */
@@ -36,82 +45,70 @@
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/mutex.h>
#include <linux/io.h> /* outb, outb_p */
+#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
-MODULE_AUTHOR("C.van Schaik");
+MODULE_AUTHOR("C. van Schaik");
MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("0.1.99");
#ifndef CONFIG_RADIO_ZOLTRIX_PORT
#define CONFIG_RADIO_ZOLTRIX_PORT -1
#endif
-static int io = CONFIG_RADIO_ZOLTRIX_PORT;
-static int radio_nr = -1;
+#define ZOLTRIX_MAX 2
+
+static int io[ZOLTRIX_MAX] = { [0] = CONFIG_RADIO_ZOLTRIX_PORT,
+ [1 ... (ZOLTRIX_MAX - 1)] = -1 };
+static int radio_nr[ZOLTRIX_MAX] = { [0 ... (ZOLTRIX_MAX - 1)] = -1 };
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
-module_param(radio_nr, int, 0);
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Zoltrix Radio Plus card (0x20c or 0x30c)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
struct zoltrix {
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- int io;
+ struct radio_isa_card isa;
int curvol;
- unsigned long curfreq;
- int muted;
- unsigned int stereo;
- struct mutex lock;
+ bool muted;
};
-static struct zoltrix zoltrix_card;
+static struct radio_isa_card *zoltrix_alloc(void)
+{
+ struct zoltrix *zol = kzalloc(sizeof(*zol), GFP_KERNEL);
+
+ return zol ? &zol->isa : NULL;
+}
-static int zol_setvol(struct zoltrix *zol, int vol)
+static int zoltrix_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
{
- zol->curvol = vol;
- if (zol->muted)
- return 0;
+ struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
- mutex_lock(&zol->lock);
- if (vol == 0) {
- outb(0, zol->io);
- outb(0, zol->io);
- inb(zol->io + 3); /* Zoltrix needs to be read to confirm */
- mutex_unlock(&zol->lock);
+ zol->curvol = vol;
+ zol->muted = mute;
+ if (mute || vol == 0) {
+ outb(0, isa->io);
+ outb(0, isa->io);
+ inb(isa->io + 3); /* Zoltrix needs to be read to confirm */
return 0;
}
- outb(zol->curvol-1, zol->io);
+ outb(vol - 1, isa->io);
msleep(10);
- inb(zol->io + 2);
- mutex_unlock(&zol->lock);
+ inb(isa->io + 2);
return 0;
}
-static void zol_mute(struct zoltrix *zol)
-{
- zol->muted = 1;
- mutex_lock(&zol->lock);
- outb(0, zol->io);
- outb(0, zol->io);
- inb(zol->io + 3); /* Zoltrix needs to be read to confirm */
- mutex_unlock(&zol->lock);
-}
-
-static void zol_unmute(struct zoltrix *zol)
-{
- zol->muted = 0;
- zol_setvol(zol, zol->curvol);
-}
-
-static int zol_setfreq(struct zoltrix *zol, unsigned long freq)
+/* tunes the radio to the desired frequency */
+static int zoltrix_s_frequency(struct radio_isa_card *isa, u32 freq)
{
- /* tunes the radio to the desired frequency */
- struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
+ struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
+ struct v4l2_device *v4l2_dev = &isa->v4l2_dev;
unsigned long long bitmask, f, m;
- unsigned int stereo = zol->stereo;
+ bool stereo = isa->stereo;
int i;
if (freq == 0) {
@@ -125,340 +122,125 @@ static int zol_setfreq(struct zoltrix *zol, unsigned long freq)
bitmask = 0xc480402c10080000ull;
i = 45;
- mutex_lock(&zol->lock);
-
- zol->curfreq = freq;
-
- outb(0, zol->io);
- outb(0, zol->io);
- inb(zol->io + 3); /* Zoltrix needs to be read to confirm */
+ outb(0, isa->io);
+ outb(0, isa->io);
+ inb(isa->io + 3); /* Zoltrix needs to be read to confirm */
- outb(0x40, zol->io);
- outb(0xc0, zol->io);
+ outb(0x40, isa->io);
+ outb(0xc0, isa->io);
bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31));
while (i--) {
if ((bitmask & 0x8000000000000000ull) != 0) {
- outb(0x80, zol->io);
+ outb(0x80, isa->io);
udelay(50);
- outb(0x00, zol->io);
+ outb(0x00, isa->io);
udelay(50);
- outb(0x80, zol->io);
+ outb(0x80, isa->io);
udelay(50);
} else {
- outb(0xc0, zol->io);
+ outb(0xc0, isa->io);
udelay(50);
- outb(0x40, zol->io);
+ outb(0x40, isa->io);
udelay(50);
- outb(0xc0, zol->io);
+ outb(0xc0, isa->io);
udelay(50);
}
bitmask *= 2;
}
/* termination sequence */
- outb(0x80, zol->io);
- outb(0xc0, zol->io);
- outb(0x40, zol->io);
+ outb(0x80, isa->io);
+ outb(0xc0, isa->io);
+ outb(0x40, isa->io);
udelay(1000);
- inb(zol->io + 2);
-
+ inb(isa->io + 2);
udelay(1000);
- if (zol->muted) {
- outb(0, zol->io);
- outb(0, zol->io);
- inb(zol->io + 3);
- udelay(1000);
- }
-
- mutex_unlock(&zol->lock);
-
- if (!zol->muted)
- zol_setvol(zol, zol->curvol);
- return 0;
+ return zoltrix_s_mute_volume(isa, zol->muted, zol->curvol);
}
/* Get signal strength */
-static int zol_getsigstr(struct zoltrix *zol)
+static u32 zoltrix_g_rxsubchans(struct radio_isa_card *isa)
{
+ struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
int a, b;
- mutex_lock(&zol->lock);
- outb(0x00, zol->io); /* This stuff I found to do nothing */
- outb(zol->curvol, zol->io);
+ outb(0x00, isa->io); /* This stuff I found to do nothing */
+ outb(zol->curvol, isa->io);
msleep(20);
- a = inb(zol->io);
+ a = inb(isa->io);
msleep(10);
- b = inb(zol->io);
+ b = inb(isa->io);
- mutex_unlock(&zol->lock);
-
- if (a != b)
- return 0;
-
- /* I found this out by playing with a binary scanner on the card io */
- return a == 0xcf || a == 0xdf || a == 0xef;
+ return (a == b && a == 0xcf) ?
+ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
}
-static int zol_is_stereo(struct zoltrix *zol)
+static u32 zoltrix_g_signal(struct radio_isa_card *isa)
{
- int x1, x2;
-
- mutex_lock(&zol->lock);
+ struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
+ int a, b;
- outb(0x00, zol->io);
- outb(zol->curvol, zol->io);
+ outb(0x00, isa->io); /* This stuff I found to do nothing */
+ outb(zol->curvol, isa->io);
msleep(20);
- x1 = inb(zol->io);
+ a = inb(isa->io);
msleep(10);
- x2 = inb(zol->io);
-
- mutex_unlock(&zol->lock);
-
- return x1 == x2 && x1 == 0xcf;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver));
- strlcpy(v->card, "Zoltrix Radio", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- struct zoltrix *zol = video_drvdata(file);
-
- if (v->index > 0)
- return -EINVAL;
-
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = 88 * 16000;
- v->rangehigh = 108 * 16000;
- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- v->capability = V4L2_TUNER_CAP_LOW;
- if (zol_is_stereo(zol))
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xFFFF * zol_getsigstr(zol);
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct zoltrix *zol = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- if (zol_setfreq(zol, f->frequency) != 0)
- return -EINVAL;
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct zoltrix *zol = video_drvdata(file);
+ b = inb(isa->io);
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = zol->curfreq;
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535);
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct zoltrix *zol = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = zol->muted;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = zol->curvol * 4096;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct zoltrix *zol = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- zol_mute(zol);
- else {
- zol_unmute(zol);
- zol_setvol(zol, zol->curvol);
- }
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- zol_setvol(zol, ctrl->value / 4096);
+ if (a != b)
return 0;
- }
- zol->stereo = 1;
- if (zol_setfreq(zol, zol->curfreq) != 0)
- return -EINVAL;
-#if 0
-/* FIXME: Implement stereo/mono switch on V4L2 */
- if (v->mode & VIDEO_SOUND_STEREO) {
- zol->stereo = 1;
- zol_setfreq(zol, zol->curfreq);
- }
- if (v->mode & VIDEO_SOUND_MONO) {
- zol->stereo = 0;
- zol_setfreq(zol, zol->curfreq);
- }
-#endif
- return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
+ /* I found this out by playing with a binary scanner on the card io */
+ return (a == 0xcf || a == 0xdf || a == 0xef) ? 0xffff : 0;
}
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
+static int zoltrix_s_stereo(struct radio_isa_card *isa, bool stereo)
{
- return a->index ? -EINVAL : 0;
+ return zoltrix_s_frequency(isa, isa->freq);
}
-static const struct v4l2_file_operations zoltrix_fops =
-{
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops zoltrix_ops = {
+ .alloc = zoltrix_alloc,
+ .s_mute_volume = zoltrix_s_mute_volume,
+ .s_frequency = zoltrix_s_frequency,
+ .s_stereo = zoltrix_s_stereo,
+ .g_rxsubchans = zoltrix_g_rxsubchans,
+ .g_signal = zoltrix_g_signal,
};
-static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
+static const int zoltrix_ioports[] = { 0x20c, 0x30c };
+
+static struct radio_isa_driver zoltrix_driver = {
+ .driver = {
+ .match = radio_isa_match,
+ .probe = radio_isa_probe,
+ .remove = radio_isa_remove,
+ .driver = {
+ .name = "radio-zoltrix",
+ },
+ },
+ .io_params = io,
+ .radio_nr_params = radio_nr,
+ .io_ports = zoltrix_ioports,
+ .num_of_io_ports = ARRAY_SIZE(zoltrix_ioports),
+ .region_size = 2,
+ .card = "Zoltrix Radio Plus",
+ .ops = &zoltrix_ops,
+ .has_stereo = true,
+ .max_volume = 15,
};
static int __init zoltrix_init(void)
{
- struct zoltrix *zol = &zoltrix_card;
- struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
- int res;
-
- strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name));
- zol->io = io;
- if (zol->io == -1) {
- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n");
- return -EINVAL;
- }
- if (zol->io != 0x20c && zol->io != 0x30c) {
- v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n");
- return -ENXIO;
- }
-
- if (!request_region(zol->io, 2, "zoltrix")) {
- v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io);
- return -EBUSY;
- }
-
- res = v4l2_device_register(NULL, v4l2_dev);
- if (res < 0) {
- release_region(zol->io, 2);
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- return res;
- }
-
- mutex_init(&zol->lock);
-
- /* mute card - prevents noisy bootups */
-
- /* this ensures that the volume is all the way down */
-
- outb(0, zol->io);
- outb(0, zol->io);
- msleep(20);
- inb(zol->io + 3);
-
- zol->curvol = 0;
- zol->stereo = 1;
-
- strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
- zol->vdev.v4l2_dev = v4l2_dev;
- zol->vdev.fops = &zoltrix_fops;
- zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
- zol->vdev.release = video_device_release_empty;
- video_set_drvdata(&zol->vdev, zol);
-
- if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(zol->io, 2);
- return -EINVAL;
- }
- v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
-
- return 0;
+ return isa_register_driver(&zoltrix_driver.driver, ZOLTRIX_MAX);
}
static void __exit zoltrix_exit(void)
{
- struct zoltrix *zol = &zoltrix_card;
-
- video_unregister_device(&zol->vdev);
- v4l2_device_unregister(&zol->v4l2_dev);
- release_region(zol->io, 2);
+ isa_unregister_driver(&zoltrix_driver.driver);
}
module_init(zoltrix_init);
diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c
index b1193dfc5087..9474706350f8 100644
--- a/drivers/media/radio/saa7706h.c
+++ b/drivers/media/radio/saa7706h.c
@@ -434,18 +434,7 @@ static struct i2c_driver saa7706h_driver = {
.id_table = saa7706h_id,
};
-static __init int saa7706h_init(void)
-{
- return i2c_add_driver(&saa7706h_driver);
-}
-
-static __exit void saa7706h_exit(void)
-{
- i2c_del_driver(&saa7706h_driver);
-}
-
-module_init(saa7706h_init);
-module_exit(saa7706h_exit);
+module_i2c_driver(saa7706h_driver);
MODULE_DESCRIPTION("SAA7706H Car Radio DSP driver");
MODULE_AUTHOR("Mocean Laboratories");
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index fd3541b0e91c..9b546a5523f3 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -539,33 +539,7 @@ static struct i2c_driver si470x_i2c_driver = {
.id_table = si470x_i2c_id,
};
-
-
-/**************************************************************************
- * Module Interface
- **************************************************************************/
-
-/*
- * si470x_i2c_init - module init
- */
-static int __init si470x_i2c_init(void)
-{
- printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
- return i2c_add_driver(&si470x_i2c_driver);
-}
-
-
-/*
- * si470x_i2c_exit - module exit
- */
-static void __exit si470x_i2c_exit(void)
-{
- i2c_del_driver(&si470x_i2c_driver);
-}
-
-
-module_init(si470x_i2c_init);
-module_exit(si470x_i2c_exit);
+module_i2c_driver(si470x_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c
index 27aba936fb2b..b898c8925ab7 100644
--- a/drivers/media/radio/si4713-i2c.c
+++ b/drivers/media/radio/si4713-i2c.c
@@ -2106,17 +2106,4 @@ static struct i2c_driver si4713_i2c_driver = {
.id_table = si4713_id,
};
-/* Module Interface */
-static int __init si4713_module_init(void)
-{
- return i2c_add_driver(&si4713_i2c_driver);
-}
-
-static void __exit si4713_module_exit(void)
-{
- i2c_del_driver(&si4713_i2c_driver);
-}
-
-module_init(si4713_module_init);
-module_exit(si4713_module_exit);
-
+module_i2c_driver(si4713_i2c_driver);
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index 0991e1973678..6418c4c9faf1 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -118,9 +118,11 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
i2cmsg[2] = pll & 0xff;
err = i2c_master_send(client, i2cmsg, sizeof(i2cmsg));
- if (!err)
- state->freq = f->frequency;
- return err;
+ if (err != sizeof(i2cmsg))
+ return err < 0 ? err : -EIO;
+
+ state->freq = f->frequency;
+ return 0;
}
static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
@@ -213,20 +215,8 @@ static struct i2c_driver tef6862_driver = {
.id_table = tef6862_id,
};
-static __init int tef6862_init(void)
-{
- return i2c_add_driver(&tef6862_driver);
-}
-
-static __exit void tef6862_exit(void)
-{
- i2c_del_driver(&tef6862_driver);
-}
-
-module_init(tef6862_init);
-module_exit(tef6862_exit);
+module_i2c_driver(tef6862_driver);
MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner");
MODULE_AUTHOR("Mocean Laboratories");
MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig
index 749f67b192e7..ea1e6545df36 100644
--- a/drivers/media/radio/wl128x/Kconfig
+++ b/drivers/media/radio/wl128x/Kconfig
@@ -4,8 +4,8 @@
menu "Texas Instruments WL128x FM driver (ST based)"
config RADIO_WL128X
tristate "Texas Instruments WL128x FM Radio"
- depends on VIDEO_V4L2 && RFKILL
- select TI_ST
+ depends on VIDEO_V4L2 && RFKILL && GPIOLIB
+ select TI_ST if NET
help
Choose Y here if you have this FM radio chip.
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index 5991ab60303d..bf867a6b5ea0 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -387,7 +387,7 @@ static void send_tasklet(unsigned long arg)
* Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for
* transmission
*/
-static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
+static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
int payload_len, struct completion *wait_completion)
{
struct sk_buff *skb;
@@ -456,13 +456,13 @@ static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
}
/* Sends FM Channel-8 command to the chip and waits for the response */
-u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
+int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
unsigned int payload_len, void *response, int *response_len)
{
struct sk_buff *skb;
struct fm_event_msg_hdr *evt_hdr;
unsigned long flags;
- u32 ret;
+ int ret;
init_completion(&fmdev->maintask_comp);
ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len,
@@ -470,8 +470,8 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
if (ret)
return ret;
- ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT);
- if (!ret) {
+ if (!wait_for_completion_timeout(&fmdev->maintask_comp,
+ FM_DRV_TX_TIMEOUT)) {
fmerr("Timeout(%d sec),didn't get reg"
"completion signal from RX tasklet\n",
jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
@@ -508,7 +508,7 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
}
/* --- Helper functions used in FM interrupt handlers ---*/
-static inline u32 check_cmdresp_status(struct fmdev *fmdev,
+static inline int check_cmdresp_status(struct fmdev *fmdev,
struct sk_buff **skb)
{
struct fm_event_msg_hdr *fm_evt_hdr;
@@ -1058,7 +1058,7 @@ static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev)
}
/* Returns availability of RDS data in internel buffer */
-u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file,
+int fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file,
struct poll_table_struct *pts)
{
poll_wait(file, &fmdev->rx.rds.read_queue, pts);
@@ -1069,7 +1069,7 @@ u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file,
}
/* Copies RDS data from internal buffer to user buffer */
-u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
+int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
u8 __user *buf, size_t count)
{
u32 block_count;
@@ -1113,7 +1113,7 @@ u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
return ret;
}
-u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set)
+int fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set)
{
switch (fmdev->curr_fmmode) {
case FM_MODE_RX:
@@ -1127,7 +1127,7 @@ u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set)
}
}
-u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq)
+int fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq)
{
if (fmdev->rx.freq == FM_UNDEFINED_FREQ) {
fmerr("RX frequency is not set\n");
@@ -1153,7 +1153,7 @@ u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq)
}
-u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set)
+int fmc_set_region(struct fmdev *fmdev, u8 region_to_set)
{
switch (fmdev->curr_fmmode) {
case FM_MODE_RX:
@@ -1167,7 +1167,7 @@ u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set)
}
}
-u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+int fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
{
switch (fmdev->curr_fmmode) {
case FM_MODE_RX:
@@ -1181,7 +1181,7 @@ u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
}
}
-u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+int fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode)
{
switch (fmdev->curr_fmmode) {
case FM_MODE_RX:
@@ -1195,7 +1195,7 @@ u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode)
}
}
-u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+int fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
{
switch (fmdev->curr_fmmode) {
case FM_MODE_RX:
@@ -1210,10 +1210,10 @@ u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
}
/* Sends power off command to the chip */
-static u32 fm_power_down(struct fmdev *fmdev)
+static int fm_power_down(struct fmdev *fmdev)
{
u16 payload;
- u32 ret;
+ int ret;
if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
fmerr("FM core is not ready\n");
@@ -1234,7 +1234,7 @@ static u32 fm_power_down(struct fmdev *fmdev)
}
/* Reads init command from FM firmware file and loads to the chip */
-static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name)
+static int fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name)
{
const struct firmware *fw_entry;
struct bts_header *fw_header;
@@ -1299,7 +1299,7 @@ rel_fw:
}
/* Loads default RX configuration to the chip */
-static u32 load_default_rx_configuration(struct fmdev *fmdev)
+static int load_default_rx_configuration(struct fmdev *fmdev)
{
int ret;
@@ -1311,7 +1311,7 @@ static u32 load_default_rx_configuration(struct fmdev *fmdev)
}
/* Does FM power on sequence */
-static u32 fm_power_up(struct fmdev *fmdev, u8 mode)
+static int fm_power_up(struct fmdev *fmdev, u8 mode)
{
u16 payload, asic_id, asic_ver;
int resp_len, ret;
@@ -1374,7 +1374,7 @@ rel:
}
/* Set FM Modes(TX, RX, OFF) */
-u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode)
+int fmc_set_mode(struct fmdev *fmdev, u8 fm_mode)
{
int ret = 0;
@@ -1427,7 +1427,7 @@ u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode)
}
/* Returns current FM mode (TX, RX, OFF) */
-u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode)
+int fmc_get_mode(struct fmdev *fmdev, u8 *fmmode)
{
if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
fmerr("FM core is not ready\n");
@@ -1483,10 +1483,10 @@ static void fm_st_reg_comp_cb(void *arg, char data)
* This function will be called from FM V4L2 open function.
* Register with ST driver and initialize driver data.
*/
-u32 fmc_prepare(struct fmdev *fmdev)
+int fmc_prepare(struct fmdev *fmdev)
{
static struct st_proto_s fm_st_proto;
- u32 ret;
+ int ret;
if (test_bit(FM_CORE_READY, &fmdev->flag)) {
fmdbg("FM Core is already up\n");
@@ -1512,10 +1512,8 @@ u32 fmc_prepare(struct fmdev *fmdev)
fmdev->streg_cbdata = -EINPROGRESS;
fmdbg("%s waiting for ST reg completion signal\n", __func__);
- ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp,
- FM_ST_REG_TIMEOUT);
-
- if (!ret) {
+ if (!wait_for_completion_timeout(&wait_for_fmdrv_reg_comp,
+ FM_ST_REG_TIMEOUT)) {
fmerr("Timeout(%d sec), didn't get reg "
"completion signal from ST\n",
jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000);
@@ -1589,10 +1587,10 @@ u32 fmc_prepare(struct fmdev *fmdev)
* This function will be called from FM V4L2 release function.
* Unregister from ST driver.
*/
-u32 fmc_release(struct fmdev *fmdev)
+int fmc_release(struct fmdev *fmdev)
{
static struct st_proto_s fm_st_proto;
- u32 ret;
+ int ret;
if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
fmdbg("FM Core is already down\n");
@@ -1631,7 +1629,7 @@ u32 fmc_release(struct fmdev *fmdev)
static int __init fm_drv_init(void)
{
struct fmdev *fmdev = NULL;
- u32 ret = -ENOMEM;
+ int ret = -ENOMEM;
fmdbg("FM driver version %s\n", FM_DRV_VERSION);
diff --git a/drivers/media/radio/wl128x/fmdrv_common.h b/drivers/media/radio/wl128x/fmdrv_common.h
index aee243bb6630..d9b9c6cf83b4 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.h
+++ b/drivers/media/radio/wl128x/fmdrv_common.h
@@ -368,27 +368,27 @@ struct fm_event_msg_hdr {
#define FM_TX_ANT_IMP_500 2
/* Functions exported by FM common sub-module */
-u32 fmc_prepare(struct fmdev *);
-u32 fmc_release(struct fmdev *);
+int fmc_prepare(struct fmdev *);
+int fmc_release(struct fmdev *);
void fmc_update_region_info(struct fmdev *, u8);
-u32 fmc_send_cmd(struct fmdev *, u8, u16,
+int fmc_send_cmd(struct fmdev *, u8, u16,
void *, unsigned int, void *, int *);
-u32 fmc_is_rds_data_available(struct fmdev *, struct file *,
+int fmc_is_rds_data_available(struct fmdev *, struct file *,
struct poll_table_struct *);
-u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *,
+int fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *,
u8 __user *, size_t);
-u32 fmc_set_freq(struct fmdev *, u32);
-u32 fmc_set_mode(struct fmdev *, u8);
-u32 fmc_set_region(struct fmdev *, u8);
-u32 fmc_set_mute_mode(struct fmdev *, u8);
-u32 fmc_set_stereo_mono(struct fmdev *, u16);
-u32 fmc_set_rds_mode(struct fmdev *, u8);
+int fmc_set_freq(struct fmdev *, u32);
+int fmc_set_mode(struct fmdev *, u8);
+int fmc_set_region(struct fmdev *, u8);
+int fmc_set_mute_mode(struct fmdev *, u8);
+int fmc_set_stereo_mono(struct fmdev *, u16);
+int fmc_set_rds_mode(struct fmdev *, u8);
-u32 fmc_get_freq(struct fmdev *, u32 *);
-u32 fmc_get_region(struct fmdev *, u8 *);
-u32 fmc_get_mode(struct fmdev *, u8 *);
+int fmc_get_freq(struct fmdev *, u32 *);
+int fmc_get_region(struct fmdev *, u8 *);
+int fmc_get_mode(struct fmdev *, u8 *);
/*
* channel spacing
diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c
index ec529b55b040..43fb72291bea 100644
--- a/drivers/media/radio/wl128x/fmdrv_rx.c
+++ b/drivers/media/radio/wl128x/fmdrv_rx.c
@@ -43,12 +43,13 @@ void fm_rx_reset_station_info(struct fmdev *fmdev)
fmdev->rx.stat_info.af_list_max = 0;
}
-u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
+int fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
{
unsigned long timeleft;
u16 payload, curr_frq, intr_flag;
u32 curr_frq_in_khz;
- u32 ret, resp_len;
+ u32 resp_len;
+ int ret;
if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) {
fmerr("Invalid frequency %d\n", freq);
@@ -141,10 +142,10 @@ exit:
return ret;
}
-static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
+static int fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
{
u16 payload;
- u32 ret;
+ int ret;
if (spacing > 0 && spacing <= 50000)
spacing = FM_CHANNEL_SPACING_50KHZ;
@@ -165,7 +166,7 @@ static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
return ret;
}
-u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
+int fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
u32 wrap_around, u32 spacing)
{
u32 resp_len;
@@ -173,7 +174,7 @@ u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
u16 payload, int_reason, intr_flag;
u16 offset, space_idx;
unsigned long timeleft;
- u32 ret;
+ int ret;
/* Set channel spacing */
ret = fm_rx_set_channel_spacing(fmdev, spacing);
@@ -296,10 +297,10 @@ again:
return ret;
}
-u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
+int fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
{
u16 payload;
- u32 ret;
+ int ret;
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -322,7 +323,7 @@ u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
}
/* Get volume */
-u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
+int fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
{
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -338,7 +339,7 @@ u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
}
/* To get current band's bottom and top frequency */
-u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq)
+int fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq)
{
if (bot_freq != NULL)
*bot_freq = fmdev->rx.region.bot_freq;
@@ -356,11 +357,11 @@ void fm_rx_get_region(struct fmdev *fmdev, u8 *region)
}
/* Sets band (0-Europe/US; 1-Japan) */
-u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
+int fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
{
u16 payload;
u32 new_frq = 0;
- u32 ret;
+ int ret;
if (region_to_set != FM_BAND_EUROPE_US &&
region_to_set != FM_BAND_JAPAN) {
@@ -399,7 +400,7 @@ u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
}
/* Reads current mute mode (Mute Off/On/Attenuate)*/
-u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
+int fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
{
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -414,10 +415,10 @@ u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
return 0;
}
-static u32 fm_config_rx_mute_reg(struct fmdev *fmdev)
+static int fm_config_rx_mute_reg(struct fmdev *fmdev)
{
u16 payload, muteval;
- u32 ret;
+ int ret;
muteval = 0;
switch (fmdev->rx.mute_mode) {
@@ -448,10 +449,10 @@ static u32 fm_config_rx_mute_reg(struct fmdev *fmdev)
}
/* Configures mute mode (Mute Off/On/Attenuate) */
-u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+int fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
{
u8 org_state;
- u32 ret;
+ int ret;
if (fmdev->rx.mute_mode == mute_mode_toset)
return 0;
@@ -469,7 +470,7 @@ u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
}
/* Gets RF dependent soft mute mode enable/disable status */
-u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
+int fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
{
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -485,10 +486,10 @@ u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
}
/* Sets RF dependent soft mute mode */
-u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
+int fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
{
u8 org_state;
- u32 ret;
+ int ret;
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -514,11 +515,11 @@ u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
}
/* Returns the signal strength level of current channel */
-u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
+int fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
{
u16 curr_rssi_lel;
u32 resp_len;
- u32 ret;
+ int ret;
if (rssilvl == NULL) {
fmerr("Invalid memory\n");
@@ -539,10 +540,10 @@ u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
* Sets the signal strength level that once reached
* will stop the auto search process
*/
-u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
+int fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
{
u16 payload;
- u32 ret;
+ int ret;
if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN ||
rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) {
@@ -561,7 +562,7 @@ u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
}
/* Returns current RX RSSI threshold value */
-u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
+int fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
{
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -577,10 +578,10 @@ u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
}
/* Sets RX stereo/mono modes */
-u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+int fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
{
u16 payload;
- u32 ret;
+ int ret;
if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) {
fmerr("Invalid mode\n");
@@ -605,10 +606,11 @@ u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
}
/* Gets current RX stereo/mono mode */
-u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
+int fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
{
u16 curr_mode;
- u32 ret, resp_len;
+ u32 resp_len;
+ int ret;
if (mode == NULL) {
fmerr("Invalid memory\n");
@@ -626,10 +628,10 @@ u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
}
/* Choose RX de-emphasis filter mode (50us/75us) */
-u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
+int fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
{
u16 payload;
- u32 ret;
+ int ret;
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -652,7 +654,7 @@ u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
}
/* Gets current RX de-emphasis filter mode */
-u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
+int fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
{
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -668,10 +670,10 @@ u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
}
/* Enable/Disable RX RDS */
-u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+int fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
{
u16 payload;
- u32 ret;
+ int ret;
if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) {
fmerr("Invalid rds option\n");
@@ -743,7 +745,7 @@ u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
}
/* Returns current RX RDS enable/disable status */
-u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
+int fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
{
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -759,10 +761,10 @@ u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
}
/* Sets RDS operation mode (RDS/RDBS) */
-u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
+int fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
{
u16 payload;
- u32 ret;
+ int ret;
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -784,7 +786,7 @@ u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
}
/* Returns current RDS operation mode */
-u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode)
+int fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode)
{
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -800,10 +802,10 @@ u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode)
}
/* Configures Alternate Frequency switch mode */
-u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
+int fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
{
u16 payload;
- u32 ret;
+ int ret;
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
@@ -831,7 +833,7 @@ u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
}
/* Returns Alternate Frequency switch status */
-u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode)
+int fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode)
{
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
diff --git a/drivers/media/radio/wl128x/fmdrv_rx.h b/drivers/media/radio/wl128x/fmdrv_rx.h
index 329e62f6be76..32add81f8d87 100644
--- a/drivers/media/radio/wl128x/fmdrv_rx.h
+++ b/drivers/media/radio/wl128x/fmdrv_rx.h
@@ -22,38 +22,38 @@
#ifndef _FMDRV_RX_H
#define _FMDRV_RX_H
-u32 fm_rx_set_freq(struct fmdev *, u32);
-u32 fm_rx_set_mute_mode(struct fmdev *, u8);
-u32 fm_rx_set_stereo_mono(struct fmdev *, u16);
-u32 fm_rx_set_rds_mode(struct fmdev *, u8);
-u32 fm_rx_set_rds_system(struct fmdev *, u8);
-u32 fm_rx_set_volume(struct fmdev *, u16);
-u32 fm_rx_set_rssi_threshold(struct fmdev *, short);
-u32 fm_rx_set_region(struct fmdev *, u8);
-u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8);
-u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16);
-u32 fm_rx_set_af_switch(struct fmdev *, u8);
+int fm_rx_set_freq(struct fmdev *, u32);
+int fm_rx_set_mute_mode(struct fmdev *, u8);
+int fm_rx_set_stereo_mono(struct fmdev *, u16);
+int fm_rx_set_rds_mode(struct fmdev *, u8);
+int fm_rx_set_rds_system(struct fmdev *, u8);
+int fm_rx_set_volume(struct fmdev *, u16);
+int fm_rx_set_rssi_threshold(struct fmdev *, short);
+int fm_rx_set_region(struct fmdev *, u8);
+int fm_rx_set_rfdepend_softmute(struct fmdev *, u8);
+int fm_rx_set_deemphasis_mode(struct fmdev *, u16);
+int fm_rx_set_af_switch(struct fmdev *, u8);
void fm_rx_reset_rds_cache(struct fmdev *);
void fm_rx_reset_station_info(struct fmdev *);
-u32 fm_rx_seek(struct fmdev *, u32, u32, u32);
+int fm_rx_seek(struct fmdev *, u32, u32, u32);
-u32 fm_rx_get_rds_mode(struct fmdev *, u8 *);
-u32 fm_rx_get_rds_system(struct fmdev *, u8 *);
-u32 fm_rx_get_mute_mode(struct fmdev *, u8 *);
-u32 fm_rx_get_volume(struct fmdev *, u16 *);
-u32 fm_rx_get_band_freq_range(struct fmdev *,
+int fm_rx_get_rds_mode(struct fmdev *, u8 *);
+int fm_rx_get_rds_system(struct fmdev *, u8 *);
+int fm_rx_get_mute_mode(struct fmdev *, u8 *);
+int fm_rx_get_volume(struct fmdev *, u16 *);
+int fm_rx_get_band_freq_range(struct fmdev *,
u32 *, u32 *);
-u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *);
-u32 fm_rx_get_rssi_level(struct fmdev *, u16 *);
-u32 fm_rx_get_rssi_threshold(struct fmdev *, short *);
-u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *);
-u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *);
-u32 fm_rx_get_af_switch(struct fmdev *, u8 *);
+int fm_rx_get_stereo_mono(struct fmdev *, u16 *);
+int fm_rx_get_rssi_level(struct fmdev *, u16 *);
+int fm_rx_get_rssi_threshold(struct fmdev *, short *);
+int fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *);
+int fm_rx_get_deemph_mode(struct fmdev *, u16 *);
+int fm_rx_get_af_switch(struct fmdev *, u8 *);
void fm_rx_get_region(struct fmdev *, u8 *);
-u32 fm_rx_set_chanl_spacing(struct fmdev *, u8);
-u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *);
+int fm_rx_set_chanl_spacing(struct fmdev *, u8);
+int fm_rx_get_chanl_spacing(struct fmdev *, u8 *);
#endif
diff --git a/drivers/media/radio/wl128x/fmdrv_tx.c b/drivers/media/radio/wl128x/fmdrv_tx.c
index be54068b56a8..6ea33e09d63b 100644
--- a/drivers/media/radio/wl128x/fmdrv_tx.c
+++ b/drivers/media/radio/wl128x/fmdrv_tx.c
@@ -24,10 +24,10 @@
#include "fmdrv_common.h"
#include "fmdrv_tx.h"
-u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+int fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
{
u16 payload;
- u32 ret;
+ int ret;
if (fmdev->tx_data.aud_mode == mode)
return 0;
@@ -46,10 +46,10 @@ u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
return ret;
}
-static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text)
+static int set_rds_text(struct fmdev *fmdev, u8 *rds_text)
{
u16 payload;
- u32 ret;
+ int ret;
ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text,
strlen(rds_text), NULL, NULL);
@@ -66,10 +66,10 @@ static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text)
return 0;
}
-static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode)
+static int set_rds_data_mode(struct fmdev *fmdev, u8 mode)
{
u16 payload;
- u32 ret;
+ int ret;
/* Setting unique PI TODO: how unique? */
payload = (u16)0xcafe;
@@ -89,10 +89,10 @@ static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode)
return 0;
}
-static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len)
+static int set_rds_len(struct fmdev *fmdev, u8 type, u16 len)
{
u16 payload;
- u32 ret;
+ int ret;
len |= type << 8;
payload = len;
@@ -105,10 +105,10 @@ static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len)
return 0;
}
-u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+int fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
{
u16 payload;
- u32 ret;
+ int ret;
u8 rds_text[] = "Zoom2\n";
fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis,
@@ -148,10 +148,10 @@ u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
return 0;
}
-u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type)
+int fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type)
{
u16 payload;
- u32 ret;
+ int ret;
if (fmdev->curr_fmmode != FM_MODE_TX)
return -EPERM;
@@ -176,10 +176,10 @@ u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type)
return 0;
}
-u32 fm_tx_set_af(struct fmdev *fmdev, u32 af)
+int fm_tx_set_af(struct fmdev *fmdev, u32 af)
{
u16 payload;
- u32 ret;
+ int ret;
if (fmdev->curr_fmmode != FM_MODE_TX)
return -EPERM;
@@ -196,10 +196,10 @@ u32 fm_tx_set_af(struct fmdev *fmdev, u32 af)
return 0;
}
-u32 fm_tx_set_region(struct fmdev *fmdev, u8 region)
+int fm_tx_set_region(struct fmdev *fmdev, u8 region)
{
u16 payload;
- u32 ret;
+ int ret;
if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) {
fmerr("Invalid band\n");
@@ -216,10 +216,10 @@ u32 fm_tx_set_region(struct fmdev *fmdev, u8 region)
return 0;
}
-u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+int fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
{
u16 payload;
- u32 ret;
+ int ret;
fmdbg("tx: mute mode %d\n", mute_mode_toset);
@@ -233,11 +233,11 @@ u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
}
/* Set TX Audio I/O */
-static u32 set_audio_io(struct fmdev *fmdev)
+static int set_audio_io(struct fmdev *fmdev)
{
struct fmtx_data *tx = &fmdev->tx_data;
u16 payload;
- u32 ret;
+ int ret;
/* Set Audio I/O Enable */
payload = tx->audio_io;
@@ -251,12 +251,12 @@ static u32 set_audio_io(struct fmdev *fmdev)
}
/* Start TX Transmission */
-static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state)
+static int enable_xmit(struct fmdev *fmdev, u8 new_xmit_state)
{
struct fmtx_data *tx = &fmdev->tx_data;
unsigned long timeleft;
u16 payload;
- u32 ret;
+ int ret;
/* Enable POWER_ENB interrupts */
payload = FM_POW_ENB_EVENT;
@@ -289,11 +289,11 @@ static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state)
}
/* Set TX power level */
-u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl)
+int fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl)
{
u16 payload;
struct fmtx_data *tx = &fmdev->tx_data;
- u32 ret;
+ int ret;
if (fmdev->curr_fmmode != FM_MODE_TX)
return -EPERM;
@@ -328,11 +328,11 @@ u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl)
* Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us)
* Convert V4L2 specified filter values to chip specific filter values.
*/
-u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis)
+int fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis)
{
struct fmtx_data *tx = &fmdev->tx_data;
u16 payload;
- u32 ret;
+ int ret;
if (fmdev->curr_fmmode != FM_MODE_TX)
return -EPERM;
@@ -360,10 +360,11 @@ u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis)
}
/* Get the TX tuning capacitor value.*/
-u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev)
+int fm_tx_get_tune_cap_val(struct fmdev *fmdev)
{
u16 curr_val;
- u32 ret, resp_len;
+ u32 resp_len;
+ int ret;
if (fmdev->curr_fmmode != FM_MODE_TX)
return -EPERM;
@@ -379,11 +380,11 @@ u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev)
}
/* Set TX Frequency */
-u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set)
+int fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set)
{
struct fmtx_data *tx = &fmdev->tx_data;
u16 payload, chanl_index;
- u32 ret;
+ int ret;
if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) {
enable_xmit(fmdev, 0);
diff --git a/drivers/media/radio/wl128x/fmdrv_tx.h b/drivers/media/radio/wl128x/fmdrv_tx.h
index e393a2bdd49e..11ae2e4c2d03 100644
--- a/drivers/media/radio/wl128x/fmdrv_tx.h
+++ b/drivers/media/radio/wl128x/fmdrv_tx.h
@@ -22,16 +22,16 @@
#ifndef _FMDRV_TX_H
#define _FMDRV_TX_H
-u32 fm_tx_set_freq(struct fmdev *, u32);
-u32 fm_tx_set_pwr_lvl(struct fmdev *, u8);
-u32 fm_tx_set_region(struct fmdev *, u8);
-u32 fm_tx_set_mute_mode(struct fmdev *, u8);
-u32 fm_tx_set_stereo_mono(struct fmdev *, u16);
-u32 fm_tx_set_rds_mode(struct fmdev *, u8);
-u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8);
-u32 fm_tx_set_af(struct fmdev *, u32);
-u32 fm_tx_set_preemph_filter(struct fmdev *, u32);
-u32 fm_tx_get_tune_cap_val(struct fmdev *);
+int fm_tx_set_freq(struct fmdev *, u32);
+int fm_tx_set_pwr_lvl(struct fmdev *, u8);
+int fm_tx_set_region(struct fmdev *, u8);
+int fm_tx_set_mute_mode(struct fmdev *, u8);
+int fm_tx_set_stereo_mono(struct fmdev *, u16);
+int fm_tx_set_rds_mode(struct fmdev *, u8);
+int fm_tx_set_radio_text(struct fmdev *, u8 *, u8);
+int fm_tx_set_af(struct fmdev *, u32);
+int fm_tx_set_preemph_filter(struct fmdev *, u32);
+int fm_tx_get_tune_cap_val(struct fmdev *);
#endif
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index 4f5c43d2566c..077d369a0173 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -84,6 +84,7 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
struct fmdev *fmdev;
ret = copy_from_user(&rds, buf, sizeof(rds));
+ rds.text[sizeof(rds.text) - 1] = '\0';
fmdbg("(%d)type: %d, text %s, af %d\n",
ret, rds.text_type, rds.text, rds.af_freq);
if (ret)
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index aeb7f43dfb65..a3fbb21350e9 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -87,6 +87,16 @@ config IR_RC5_SZ_DECODER
uses an IR protocol that is almost standard RC-5, but not quite,
as it uses an additional bit).
+config IR_SANYO_DECODER
+ tristate "Enable IR raw decoder for the Sanyo protocol"
+ depends on RC_CORE
+ default y
+
+ ---help---
+ Enable this option if you have an infrared remote control which
+ uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes),
+ and you need software decoding support.
+
config IR_MCE_KBD_DECODER
tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
depends on RC_CORE
@@ -256,4 +266,13 @@ config RC_LOOPBACK
To compile this driver as a module, choose M here: the module will
be called rc_loopback.
+config IR_GPIO_CIR
+ tristate "GPIO IR remote control"
+ depends on RC_CORE
+ ---help---
+ Say Y if you want to use GPIO based IR Receiver.
+
+ To compile this driver as a module, choose M here: the module will
+ be called gpio-ir-recv.
+
endif #RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 2156e786b557..29f364f88a94 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
+obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
@@ -25,3 +26,4 @@ obj-$(CONFIG_IR_REDRAT3) += redrat3.o
obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
+obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 7f7079b12f23..392d4be91f8f 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -117,7 +117,7 @@ static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset)
static void cir_dump_regs(struct fintek_dev *fintek)
{
fintek_config_mode_enable(fintek);
- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME);
pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
@@ -143,7 +143,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
u8 chip_major, chip_minor;
u8 vendor_major, vendor_minor;
u8 portsel, ir_class;
- u16 vendor;
+ u16 vendor, chip;
int ret = 0;
fintek_config_mode_enable(fintek);
@@ -176,6 +176,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI);
chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO);
+ chip = chip_major << 8 | chip_minor;
vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI);
vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO);
@@ -192,6 +193,15 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
fintek->chip_major = chip_major;
fintek->chip_minor = chip_minor;
fintek->chip_vendor = vendor;
+
+ /*
+ * Newer reviews of this chipset uses port 8 instead of 5
+ */
+ if ((chip != 0x0408) || (chip != 0x0804))
+ fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV2;
+ else
+ fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV1;
+
spin_unlock_irqrestore(&fintek->fintek_lock, flags);
return ret;
@@ -200,7 +210,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
static void fintek_cir_ldev_init(struct fintek_dev *fintek)
{
/* Select CIR logical device and enable */
- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
/* Write allocated CIR address and IRQ information to hardware */
@@ -381,7 +391,7 @@ static irqreturn_t fintek_cir_isr(int irq, void *data)
fit_dbg_verbose("%s firing", __func__);
fintek_config_mode_enable(fintek);
- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
fintek_config_mode_disable(fintek);
/*
@@ -422,7 +432,7 @@ static void fintek_enable_cir(struct fintek_dev *fintek)
fintek_config_mode_enable(fintek);
/* enable the CIR logical device */
- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
fintek_config_mode_disable(fintek);
@@ -439,7 +449,7 @@ static void fintek_disable_cir(struct fintek_dev *fintek)
fintek_config_mode_enable(fintek);
/* disable the CIR logical device */
- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
fintek_config_mode_disable(fintek);
@@ -611,7 +621,7 @@ static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state)
fintek_config_mode_enable(fintek);
/* disable cir logical dev */
- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
fintek_config_mode_disable(fintek);
@@ -634,7 +644,7 @@ static int fintek_resume(struct pnp_dev *pdev)
/* Enable CIR logical device */
fintek_config_mode_enable(fintek);
- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
fintek_config_mode_disable(fintek);
diff --git a/drivers/media/rc/fintek-cir.h b/drivers/media/rc/fintek-cir.h
index 1b10b2011f5e..82516a1d39b0 100644
--- a/drivers/media/rc/fintek-cir.h
+++ b/drivers/media/rc/fintek-cir.h
@@ -88,6 +88,7 @@ struct fintek_dev {
u8 chip_major;
u8 chip_minor;
u16 chip_vendor;
+ u8 logical_dev_cir;
/* hardware features */
bool hw_learning_capable;
@@ -172,7 +173,8 @@ struct fintek_dev {
#define LOGICAL_DEV_ENABLE 0x01
/* Logical device number of the CIR function */
-#define LOGICAL_DEV_CIR 0x05
+#define LOGICAL_DEV_CIR_REV1 0x05
+#define LOGICAL_DEV_CIR_REV2 0x08
/* CIR Logical Device (LDN 0x08) config registers */
#define CIR_CR_COMMAND_INDEX 0x04
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
new file mode 100644
index 000000000000..0d875450c5ce
--- /dev/null
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -0,0 +1,205 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <media/rc-core.h>
+#include <media/gpio-ir-recv.h>
+
+#define GPIO_IR_DRIVER_NAME "gpio-rc-recv"
+#define GPIO_IR_DEVICE_NAME "gpio_ir_recv"
+
+struct gpio_rc_dev {
+ struct rc_dev *rcdev;
+ int gpio_nr;
+ bool active_low;
+};
+
+static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
+{
+ struct gpio_rc_dev *gpio_dev = dev_id;
+ int gval;
+ int rc = 0;
+ enum raw_event_type type = IR_SPACE;
+
+ gval = gpio_get_value_cansleep(gpio_dev->gpio_nr);
+
+ if (gval < 0)
+ goto err_get_value;
+
+ if (gpio_dev->active_low)
+ gval = !gval;
+
+ if (gval == 1)
+ type = IR_PULSE;
+
+ rc = ir_raw_event_store_edge(gpio_dev->rcdev, type);
+ if (rc < 0)
+ goto err_get_value;
+
+ ir_raw_event_handle(gpio_dev->rcdev);
+
+err_get_value:
+ return IRQ_HANDLED;
+}
+
+static int __devinit gpio_ir_recv_probe(struct platform_device *pdev)
+{
+ struct gpio_rc_dev *gpio_dev;
+ struct rc_dev *rcdev;
+ const struct gpio_ir_recv_platform_data *pdata =
+ pdev->dev.platform_data;
+ int rc;
+
+ if (!pdata)
+ return -EINVAL;
+
+ if (pdata->gpio_nr < 0)
+ return -EINVAL;
+
+ gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL);
+ if (!gpio_dev)
+ return -ENOMEM;
+
+ rcdev = rc_allocate_device();
+ if (!rcdev) {
+ rc = -ENOMEM;
+ goto err_allocate_device;
+ }
+
+ rcdev->driver_type = RC_DRIVER_IR_RAW;
+ rcdev->allowed_protos = RC_TYPE_ALL;
+ rcdev->input_name = GPIO_IR_DEVICE_NAME;
+ rcdev->input_id.bustype = BUS_HOST;
+ rcdev->driver_name = GPIO_IR_DRIVER_NAME;
+ rcdev->map_name = RC_MAP_EMPTY;
+
+ gpio_dev->rcdev = rcdev;
+ gpio_dev->gpio_nr = pdata->gpio_nr;
+ gpio_dev->active_low = pdata->active_low;
+
+ rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
+ if (rc < 0)
+ goto err_gpio_request;
+ rc = gpio_direction_input(pdata->gpio_nr);
+ if (rc < 0)
+ goto err_gpio_direction_input;
+
+ rc = rc_register_device(rcdev);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "failed to register rc device\n");
+ goto err_register_rc_device;
+ }
+
+ platform_set_drvdata(pdev, gpio_dev);
+
+ rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr),
+ gpio_ir_recv_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "gpio-ir-recv-irq", gpio_dev);
+ if (rc < 0)
+ goto err_request_irq;
+
+ return 0;
+
+err_request_irq:
+ platform_set_drvdata(pdev, NULL);
+ rc_unregister_device(rcdev);
+err_register_rc_device:
+err_gpio_direction_input:
+ gpio_free(pdata->gpio_nr);
+err_gpio_request:
+ rc_free_device(rcdev);
+ rcdev = NULL;
+err_allocate_device:
+ kfree(gpio_dev);
+ return rc;
+}
+
+static int __devexit gpio_ir_recv_remove(struct platform_device *pdev)
+{
+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+ free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
+ platform_set_drvdata(pdev, NULL);
+ rc_unregister_device(gpio_dev->rcdev);
+ gpio_free(gpio_dev->gpio_nr);
+ rc_free_device(gpio_dev->rcdev);
+ kfree(gpio_dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_ir_recv_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
+ else
+ disable_irq(gpio_to_irq(gpio_dev->gpio_nr));
+
+ return 0;
+}
+
+static int gpio_ir_recv_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
+ else
+ enable_irq(gpio_to_irq(gpio_dev->gpio_nr));
+
+ return 0;
+}
+
+static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
+ .suspend = gpio_ir_recv_suspend,
+ .resume = gpio_ir_recv_resume,
+};
+#endif
+
+static struct platform_driver gpio_ir_recv_driver = {
+ .probe = gpio_ir_recv_probe,
+ .remove = __devexit_p(gpio_ir_recv_remove),
+ .driver = {
+ .name = GPIO_IR_DRIVER_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &gpio_ir_recv_pm_ops,
+#endif
+ },
+};
+
+static int __init gpio_ir_recv_init(void)
+{
+ return platform_driver_register(&gpio_ir_recv_driver);
+}
+module_init(gpio_ir_recv_init);
+
+static void __exit gpio_ir_recv_exit(void)
+{
+ platform_driver_unregister(&gpio_ir_recv_driver);
+}
+module_exit(gpio_ir_recv_exit);
+
+MODULE_DESCRIPTION("GPIO IR Receiver driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 3aeb29a7ce11..7f26fdf2e54e 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -47,7 +47,7 @@
#define MOD_AUTHOR "Jarod Wilson <jarod@wilsonet.com>"
#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display"
#define MOD_NAME "imon"
-#define MOD_VERSION "0.9.3"
+#define MOD_VERSION "0.9.4"
#define DISPLAY_MINOR_BASE 144
#define DEVICE_NAME "lcd%d"
@@ -1658,9 +1658,17 @@ static void usb_rx_callback_intf0(struct urb *urb)
return;
ictx = (struct imon_context *)urb->context;
- if (!ictx || !ictx->dev_present_intf0)
+ if (!ictx)
return;
+ /*
+ * if we get a callback before we're done configuring the hardware, we
+ * can't yet process the data, as there's nowhere to send it, but we
+ * still need to submit a new rx URB to avoid wedging the hardware
+ */
+ if (!ictx->dev_present_intf0)
+ goto out;
+
switch (urb->status) {
case -ENOENT: /* usbcore unlink successful! */
return;
@@ -1678,6 +1686,7 @@ static void usb_rx_callback_intf0(struct urb *urb)
break;
}
+out:
usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC);
}
@@ -1690,9 +1699,17 @@ static void usb_rx_callback_intf1(struct urb *urb)
return;
ictx = (struct imon_context *)urb->context;
- if (!ictx || !ictx->dev_present_intf1)
+ if (!ictx)
return;
+ /*
+ * if we get a callback before we're done configuring the hardware, we
+ * can't yet process the data, as there's nowhere to send it, but we
+ * still need to submit a new rx URB to avoid wedging the hardware
+ */
+ if (!ictx->dev_present_intf1)
+ goto out;
+
switch (urb->status) {
case -ENOENT: /* usbcore unlink successful! */
return;
@@ -1710,6 +1727,7 @@ static void usb_rx_callback_intf1(struct urb *urb)
break;
}
+out:
usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
}
@@ -2242,7 +2260,7 @@ find_endpoint_failed:
mutex_unlock(&ictx->lock);
usb_free_urb(rx_urb);
rx_urb_alloc_failed:
- dev_err(ictx->dev, "unable to initialize intf0, err %d\n", ret);
+ dev_err(ictx->dev, "unable to initialize intf1, err %d\n", ret);
return NULL;
}
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 17f8db00435a..3c9431a9f62d 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -194,8 +194,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
return 0;
}
- IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n",
+ data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 2e5cd3100b64..95e630998aaf 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -357,6 +357,7 @@ static void init_decoders(struct work_struct *work)
load_rc6_decode();
load_jvc_decode();
load_sony_decode();
+ load_sanyo_decode();
load_mce_kbd_decode();
load_lirc_codec();
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 140fb67e2f89..4cfdd7fa4bbd 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -18,24 +18,31 @@
/*
* This decoder currently supports:
* RC6-0-16 (standard toggle bit in header)
+ * RC6-6A-20 (no toggle bit)
* RC6-6A-24 (no toggle bit)
* RC6-6A-32 (MCE version with toggle bit in body)
*/
-#define RC6_UNIT 444444 /* us */
+#define RC6_UNIT 444444 /* nanosecs */
#define RC6_HEADER_NBITS 4 /* not including toggle bit */
#define RC6_0_NBITS 16
-#define RC6_6A_SMALL_NBITS 24
-#define RC6_6A_LARGE_NBITS 32
+#define RC6_6A_32_NBITS 32
+#define RC6_6A_NBITS 128 /* Variable 8..128 */
#define RC6_PREFIX_PULSE (6 * RC6_UNIT)
#define RC6_PREFIX_SPACE (2 * RC6_UNIT)
#define RC6_BIT_START (1 * RC6_UNIT)
#define RC6_BIT_END (1 * RC6_UNIT)
#define RC6_TOGGLE_START (2 * RC6_UNIT)
#define RC6_TOGGLE_END (2 * RC6_UNIT)
+#define RC6_SUFFIX_SPACE (6 * RC6_UNIT)
#define RC6_MODE_MASK 0x07 /* for the header bits */
#define RC6_STARTBIT_MASK 0x08 /* for the header bits */
#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */
+#define RC6_6A_LCC_MASK 0xffff0000 /* RC6-6A-32 long customer code mask */
+#define RC6_6A_MCE_CC 0x800f0000 /* MCE customer code */
+#ifndef CHAR_BIT
+#define CHAR_BIT 8 /* Normally in <limits.h> */
+#endif
enum rc6_mode {
RC6_MODE_0,
@@ -125,6 +132,7 @@ again:
break;
data->state = STATE_HEADER_BIT_START;
+ data->header = 0;
return 0;
case STATE_HEADER_BIT_START:
@@ -171,20 +179,14 @@ again:
data->state = STATE_BODY_BIT_START;
decrease_duration(&ev, RC6_TOGGLE_END);
data->count = 0;
+ data->body = 0;
switch (rc6_mode(data)) {
case RC6_MODE_0:
data->wanted_bits = RC6_0_NBITS;
break;
case RC6_MODE_6A:
- /* This might look weird, but we basically
- check the value of the first body bit to
- determine the number of bits in mode 6A */
- if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) ||
- geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
- data->wanted_bits = RC6_6A_LARGE_NBITS;
- else
- data->wanted_bits = RC6_6A_SMALL_NBITS;
+ data->wanted_bits = RC6_6A_NBITS;
break;
default:
IR_dprintk(1, "RC6 unknown mode\n");
@@ -193,15 +195,21 @@ again:
goto again;
case STATE_BODY_BIT_START:
- if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
- break;
-
- data->body <<= 1;
- if (ev.pulse)
- data->body |= 1;
- data->count++;
- data->state = STATE_BODY_BIT_END;
- return 0;
+ if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
+ /* Discard LSB's that won't fit in data->body */
+ if (data->count++ < CHAR_BIT * sizeof data->body) {
+ data->body <<= 1;
+ if (ev.pulse)
+ data->body |= 1;
+ }
+ data->state = STATE_BODY_BIT_END;
+ return 0;
+ } else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
+ geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
+ data->state = STATE_FINISHED;
+ goto again;
+ }
+ break;
case STATE_BODY_BIT_END:
if (!is_transition(&ev, &dev->raw->prev_ev))
@@ -221,20 +229,27 @@ again:
switch (rc6_mode(data)) {
case RC6_MODE_0:
- scancode = data->body & 0xffff;
+ scancode = data->body;
toggle = data->toggle;
IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
scancode, toggle);
break;
case RC6_MODE_6A:
- if (data->wanted_bits == RC6_6A_LARGE_NBITS) {
- toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0;
- scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK;
+ if (data->count > CHAR_BIT * sizeof data->body) {
+ IR_dprintk(1, "RC6 too many (%u) data bits\n",
+ data->count);
+ goto out;
+ }
+
+ scancode = data->body;
+ if (data->count == RC6_6A_32_NBITS &&
+ (scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
+ /* MCE RC */
+ toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0;
+ scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
} else {
toggle = 0;
- scancode = data->body & 0xffffff;
}
-
IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
scancode, toggle);
break;
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
new file mode 100644
index 000000000000..d38fbdd0b25a
--- /dev/null
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -0,0 +1,205 @@
+/* ir-sanyo-decoder.c - handle SANYO IR Pulse/Space protocol
+ *
+ * Copyright (C) 2011 by Mauro Carvalho Chehab <mchehab@redhat.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 of the License.
+ *
+ * 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.
+ *
+ * This protocol uses the NEC protocol timings. However, data is formatted as:
+ * 13 bits Custom Code
+ * 13 bits NOT(Custom Code)
+ * 8 bits Key data
+ * 8 bits NOT(Key data)
+ *
+ * According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon
+ * Information for this protocol is available at the Sanyo LC7461 datasheet.
+ */
+
+#include <linux/module.h>
+#include <linux/bitrev.h>
+#include "rc-core-priv.h"
+
+#define SANYO_NBITS (13+13+8+8)
+#define SANYO_UNIT 562500 /* ns */
+#define SANYO_HEADER_PULSE (16 * SANYO_UNIT)
+#define SANYO_HEADER_SPACE (8 * SANYO_UNIT)
+#define SANYO_BIT_PULSE (1 * SANYO_UNIT)
+#define SANYO_BIT_0_SPACE (1 * SANYO_UNIT)
+#define SANYO_BIT_1_SPACE (3 * SANYO_UNIT)
+#define SANYO_REPEAT_SPACE (150 * SANYO_UNIT)
+#define SANYO_TRAILER_PULSE (1 * SANYO_UNIT)
+#define SANYO_TRAILER_SPACE (10 * SANYO_UNIT) /* in fact, 42 */
+
+enum sanyo_state {
+ STATE_INACTIVE,
+ STATE_HEADER_SPACE,
+ STATE_BIT_PULSE,
+ STATE_BIT_SPACE,
+ STATE_TRAILER_PULSE,
+ STATE_TRAILER_SPACE,
+};
+
+/**
+ * ir_sanyo_decode() - Decode one SANYO pulse or space
+ * @dev: the struct rc_dev descriptor of the device
+ * @duration: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
+{
+ struct sanyo_dec *data = &dev->raw->sanyo;
+ u32 scancode;
+ u8 address, not_address, command, not_command;
+
+ if (!(dev->raw->enabled_protocols & RC_TYPE_SANYO))
+ return 0;
+
+ if (!is_timing_event(ev)) {
+ if (ev.reset) {
+ IR_dprintk(1, "SANYO event reset received. reset to state 0\n");
+ data->state = STATE_INACTIVE;
+ }
+ return 0;
+ }
+
+ IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+ switch (data->state) {
+
+ case STATE_INACTIVE:
+ if (!ev.pulse)
+ break;
+
+ if (eq_margin(ev.duration, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) {
+ data->count = 0;
+ data->state = STATE_HEADER_SPACE;
+ return 0;
+ }
+ break;
+
+
+ case STATE_HEADER_SPACE:
+ if (ev.pulse)
+ break;
+
+ if (eq_margin(ev.duration, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) {
+ data->state = STATE_BIT_PULSE;
+ return 0;
+ }
+
+ break;
+
+ case STATE_BIT_PULSE:
+ if (!ev.pulse)
+ break;
+
+ if (!eq_margin(ev.duration, SANYO_BIT_PULSE, SANYO_UNIT / 2))
+ break;
+
+ data->state = STATE_BIT_SPACE;
+ return 0;
+
+ case STATE_BIT_SPACE:
+ if (ev.pulse)
+ break;
+
+ if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
+ if (!dev->keypressed) {
+ IR_dprintk(1, "SANYO discarding last key repeat: event after key up\n");
+ } else {
+ rc_repeat(dev);
+ IR_dprintk(1, "SANYO repeat last key\n");
+ data->state = STATE_INACTIVE;
+ }
+ return 0;
+ }
+
+ data->bits <<= 1;
+ if (eq_margin(ev.duration, SANYO_BIT_1_SPACE, SANYO_UNIT / 2))
+ data->bits |= 1;
+ else if (!eq_margin(ev.duration, SANYO_BIT_0_SPACE, SANYO_UNIT / 2))
+ break;
+ data->count++;
+
+ if (data->count == SANYO_NBITS)
+ data->state = STATE_TRAILER_PULSE;
+ else
+ data->state = STATE_BIT_PULSE;
+
+ return 0;
+
+ case STATE_TRAILER_PULSE:
+ if (!ev.pulse)
+ break;
+
+ if (!eq_margin(ev.duration, SANYO_TRAILER_PULSE, SANYO_UNIT / 2))
+ break;
+
+ data->state = STATE_TRAILER_SPACE;
+ return 0;
+
+ case STATE_TRAILER_SPACE:
+ if (ev.pulse)
+ break;
+
+ if (!geq_margin(ev.duration, SANYO_TRAILER_SPACE, SANYO_UNIT / 2))
+ break;
+
+ address = bitrev16((data->bits >> 29) & 0x1fff) >> 3;
+ not_address = bitrev16((data->bits >> 16) & 0x1fff) >> 3;
+ command = bitrev8((data->bits >> 8) & 0xff);
+ not_command = bitrev8((data->bits >> 0) & 0xff);
+
+ if ((command ^ not_command) != 0xff) {
+ IR_dprintk(1, "SANYO checksum error: received 0x%08Lx\n",
+ data->bits);
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
+
+ scancode = address << 8 | command;
+ IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode);
+ rc_keydown(dev, scancode, 0);
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
+
+ IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n",
+ data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state = STATE_INACTIVE;
+ return -EINVAL;
+}
+
+static struct ir_raw_handler sanyo_handler = {
+ .protocols = RC_TYPE_SANYO,
+ .decode = ir_sanyo_decode,
+};
+
+static int __init ir_sanyo_decode_init(void)
+{
+ ir_raw_handler_register(&sanyo_handler);
+
+ printk(KERN_INFO "IR SANYO protocol handler initialized\n");
+ return 0;
+}
+
+static void __exit ir_sanyo_decode_exit(void)
+{
+ ir_raw_handler_unregister(&sanyo_handler);
+}
+
+module_init(ir_sanyo_decode_init);
+module_exit(ir_sanyo_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("SANYO IR protocol decoder");
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index d5e2b50aff1f..dab98b37621a 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -130,7 +130,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
case 15:
device = bitrev8((data->bits >> 0) & 0xFF);
subdevice = 0;
- function = bitrev8((data->bits >> 7) & 0xFD);
+ function = bitrev8((data->bits >> 7) & 0xFE);
break;
case 20:
device = bitrev8((data->bits >> 5) & 0xF8);
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 36e4d5e8dd6a..49ce2662f56b 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -41,8 +41,11 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-imon-mce.o \
rc-imon-pad.o \
rc-iodata-bctv7e.o \
+ rc-it913x-v1.o \
+ rc-it913x-v2.o \
rc-kaiomy.o \
rc-kworld-315u.o \
+ rc-kworld-pc150u.o \
rc-kworld-plus-tv-analog.o \
rc-leadtek-y04g0051.o \
rc-lirc.o \
diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c
index e51c6163378b..929bbbc16393 100644
--- a/drivers/media/rc/keymaps/rc-hauppauge.c
+++ b/drivers/media/rc/keymaps/rc-hauppauge.c
@@ -183,6 +183,57 @@ static struct rc_map_table rc5_hauppauge_new[] = {
{ 0x1d3f, KEY_HOME },
/*
+ * Keycodes for PT# R-005 remote bundled with Haupauge HVR-930C
+ * Keycodes start with address = 0x1c
+ */
+ { 0x1c3b, KEY_GOTO },
+ { 0x1c3d, KEY_POWER },
+
+ { 0x1c14, KEY_UP },
+ { 0x1c15, KEY_DOWN },
+ { 0x1c16, KEY_LEFT },
+ { 0x1c17, KEY_RIGHT },
+ { 0x1c25, KEY_OK },
+
+ { 0x1c00, KEY_0 },
+ { 0x1c01, KEY_1 },
+ { 0x1c02, KEY_2 },
+ { 0x1c03, KEY_3 },
+ { 0x1c04, KEY_4 },
+ { 0x1c05, KEY_5 },
+ { 0x1c06, KEY_6 },
+ { 0x1c07, KEY_7 },
+ { 0x1c08, KEY_8 },
+ { 0x1c09, KEY_9 },
+
+ { 0x1c1f, KEY_EXIT }, /* BACK */
+ { 0x1c0d, KEY_MENU },
+ { 0x1c1c, KEY_TV },
+
+ { 0x1c10, KEY_VOLUMEUP },
+ { 0x1c11, KEY_VOLUMEDOWN },
+
+ { 0x1c20, KEY_CHANNELUP },
+ { 0x1c21, KEY_CHANNELDOWN },
+
+ { 0x1c0f, KEY_MUTE },
+ { 0x1c12, KEY_PREVIOUS }, /* Prev */
+
+ { 0x1c36, KEY_STOP },
+ { 0x1c37, KEY_RECORD },
+
+ { 0x1c24, KEY_LAST }, /* <| */
+ { 0x1c1e, KEY_NEXT }, /* >| */
+
+ { 0x1c0a, KEY_TEXT },
+ { 0x1c0e, KEY_SUBTITLE }, /* CC */
+
+ { 0x1c32, KEY_REWIND },
+ { 0x1c30, KEY_PAUSE },
+ { 0x1c35, KEY_PLAY },
+ { 0x1c34, KEY_FASTFORWARD },
+
+ /*
* Keycodes for the old Black Remote Controller
* This one also uses RC-5 protocol
* Keycodes start with address = 0x00
diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c
new file mode 100644
index 000000000000..0ac775fd109d
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-it913x-v1.c
@@ -0,0 +1,95 @@
+/* ITE Generic remotes Version 1
+ *
+ * Copyright (C) 2012 Malcolm Priestley (tvboxspy@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.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+
+static struct rc_map_table it913x_v1_rc[] = {
+ /* Type 1 */
+ { 0x61d601, KEY_VIDEO }, /* Source */
+ { 0x61d602, KEY_3 },
+ { 0x61d603, KEY_POWER }, /* ShutDown */
+ { 0x61d604, KEY_1 },
+ { 0x61d605, KEY_5 },
+ { 0x61d606, KEY_6 },
+ { 0x61d607, KEY_CHANNELDOWN }, /* CH- */
+ { 0x61d608, KEY_2 },
+ { 0x61d609, KEY_CHANNELUP }, /* CH+ */
+ { 0x61d60a, KEY_9 },
+ { 0x61d60b, KEY_ZOOM }, /* Zoom */
+ { 0x61d60c, KEY_7 },
+ { 0x61d60d, KEY_8 },
+ { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */
+ { 0x61d60f, KEY_4 },
+ { 0x61d610, KEY_ESC }, /* [back up arrow] */
+ { 0x61d611, KEY_0 },
+ { 0x61d612, KEY_OK }, /* [enter arrow] */
+ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */
+ { 0x61d614, KEY_RECORD }, /* Rec */
+ { 0x61d615, KEY_STOP }, /* Stop */
+ { 0x61d616, KEY_PLAY }, /* Play */
+ { 0x61d617, KEY_MUTE }, /* Mute */
+ { 0x61d618, KEY_UP },
+ { 0x61d619, KEY_DOWN },
+ { 0x61d61a, KEY_LEFT },
+ { 0x61d61b, KEY_RIGHT },
+ { 0x61d61c, KEY_RED },
+ { 0x61d61d, KEY_GREEN },
+ { 0x61d61e, KEY_YELLOW },
+ { 0x61d61f, KEY_BLUE },
+ { 0x61d643, KEY_POWER2 }, /* [red power button] */
+ /* Type 2 - 20 buttons */
+ { 0x807f0d, KEY_0 },
+ { 0x807f04, KEY_1 },
+ { 0x807f05, KEY_2 },
+ { 0x807f06, KEY_3 },
+ { 0x807f07, KEY_4 },
+ { 0x807f08, KEY_5 },
+ { 0x807f09, KEY_6 },
+ { 0x807f0a, KEY_7 },
+ { 0x807f1b, KEY_8 },
+ { 0x807f1f, KEY_9 },
+ { 0x807f12, KEY_POWER },
+ { 0x807f01, KEY_MEDIA_REPEAT}, /* Recall */
+ { 0x807f19, KEY_PAUSE }, /* Timeshift */
+ { 0x807f1e, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+ { 0x807f03, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
+ { 0x807f1a, KEY_CHANNELUP },
+ { 0x807f02, KEY_CHANNELDOWN },
+ { 0x807f0c, KEY_ZOOM },
+ { 0x807f00, KEY_RECORD },
+ { 0x807f0e, KEY_STOP },
+};
+
+static struct rc_map_list it913x_v1_map = {
+ .map = {
+ .scan = it913x_v1_rc,
+ .size = ARRAY_SIZE(it913x_v1_rc),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_IT913X_V1,
+ }
+};
+
+static int __init init_rc_it913x_v1_map(void)
+{
+ return rc_map_register(&it913x_v1_map);
+}
+
+static void __exit exit_rc_it913x_v1_map(void)
+{
+ rc_map_unregister(&it913x_v1_map);
+}
+
+module_init(init_rc_it913x_v1_map)
+module_exit(exit_rc_it913x_v1_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c
new file mode 100644
index 000000000000..28e376e18b99
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-it913x-v2.c
@@ -0,0 +1,94 @@
+/* ITE Generic remotes Version 2
+ *
+ * Copyright (C) 2012 Malcolm Priestley (tvboxspy@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.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+
+static struct rc_map_table it913x_v2_rc[] = {
+ /* Type 1 */
+ /* 9005 remote */
+ { 0x807f12, KEY_POWER2 }, /* Power (RED POWER BUTTON)*/
+ { 0x807f1a, KEY_VIDEO }, /* Source */
+ { 0x807f1e, KEY_MUTE }, /* Mute */
+ { 0x807f01, KEY_RECORD }, /* Record */
+ { 0x807f02, KEY_CHANNELUP }, /* Channel+ */
+ { 0x807f03, KEY_TIME }, /* TimeShift */
+ { 0x807f04, KEY_VOLUMEUP }, /* Volume- */
+ { 0x807f05, KEY_SCREEN }, /* FullScreen */
+ { 0x807f06, KEY_VOLUMEDOWN }, /* Volume- */
+ { 0x807f07, KEY_0 }, /* 0 */
+ { 0x807f08, KEY_CHANNELDOWN }, /* Channel- */
+ { 0x807f09, KEY_PREVIOUS }, /* Recall */
+ { 0x807f0a, KEY_1 }, /* 1 */
+ { 0x807f1b, KEY_2 }, /* 2 */
+ { 0x807f1f, KEY_3 }, /* 3 */
+ { 0x807f0c, KEY_4 }, /* 4 */
+ { 0x807f0d, KEY_5 }, /* 5 */
+ { 0x807f0e, KEY_6 }, /* 6 */
+ { 0x807f00, KEY_7 }, /* 7 */
+ { 0x807f0f, KEY_8 }, /* 8 */
+ { 0x807f19, KEY_9 }, /* 9 */
+
+ /* Type 2 */
+ /* keys stereo, snapshot unassigned */
+ { 0x866b00, KEY_0 },
+ { 0x866b1b, KEY_1 },
+ { 0x866b02, KEY_2 },
+ { 0x866b03, KEY_3 },
+ { 0x866b04, KEY_4 },
+ { 0x866b05, KEY_5 },
+ { 0x866b06, KEY_6 },
+ { 0x866b07, KEY_7 },
+ { 0x866b08, KEY_8 },
+ { 0x866b09, KEY_9 },
+ { 0x866b12, KEY_POWER },
+ { 0x866b13, KEY_MUTE },
+ { 0x866b0a, KEY_PREVIOUS }, /* Recall */
+ { 0x866b1e, KEY_PAUSE },
+ { 0x866b0c, KEY_VOLUMEUP },
+ { 0x866b18, KEY_VOLUMEDOWN },
+ { 0x866b0b, KEY_CHANNELUP },
+ { 0x866b18, KEY_CHANNELDOWN },
+ { 0x866b10, KEY_ZOOM },
+ { 0x866b1d, KEY_RECORD },
+ { 0x866b0e, KEY_STOP },
+ { 0x866b11, KEY_EPG},
+ { 0x866b1a, KEY_FASTFORWARD },
+ { 0x866b0f, KEY_REWIND },
+ { 0x866b1c, KEY_TV },
+ { 0x866b1b, KEY_TEXT },
+
+};
+
+static struct rc_map_list it913x_v2_map = {
+ .map = {
+ .scan = it913x_v2_rc,
+ .size = ARRAY_SIZE(it913x_v2_rc),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_IT913X_V2,
+ }
+};
+
+static int __init init_rc_it913x_v2_map(void)
+{
+ return rc_map_register(&it913x_v2_map);
+}
+
+static void __exit exit_rc_it913x_v2_map(void)
+{
+ rc_map_unregister(&it913x_v2_map);
+}
+
+module_init(init_rc_it913x_v2_map)
+module_exit(exit_rc_it913x_v2_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c
new file mode 100644
index 000000000000..233bb5ee087f
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c
@@ -0,0 +1,102 @@
+/* kworld-pc150u.c - Keytable for kworld_pc150u Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Kyle Strickland
+ * (based on kworld-plus-tv-analog.c by
+ * Mauro Carvalho Chehab <mchehab@redhat.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.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+/* Kworld PC150-U
+ Kyle Strickland <kyle@kyle.strickland.name>
+ */
+
+static struct rc_map_table kworld_pc150u[] = {
+ { 0x0c, KEY_MEDIA }, /* Kworld key */
+ { 0x16, KEY_EJECTCLOSECD }, /* -> ) */
+ { 0x1d, KEY_POWER2 },
+
+ { 0x00, KEY_1 },
+ { 0x01, KEY_2 },
+ { 0x02, KEY_3 },
+ { 0x03, KEY_4 },
+ { 0x04, KEY_5 },
+ { 0x05, KEY_6 },
+ { 0x06, KEY_7 },
+ { 0x07, KEY_8 },
+ { 0x08, KEY_9 },
+ { 0x0a, KEY_0 },
+
+ { 0x09, KEY_AGAIN },
+ { 0x14, KEY_MUTE },
+
+ { 0x1e, KEY_LAST },
+ { 0x17, KEY_ZOOM },
+ { 0x1f, KEY_HOMEPAGE },
+ { 0x0e, KEY_ESC },
+
+ { 0x20, KEY_UP },
+ { 0x21, KEY_DOWN },
+ { 0x42, KEY_LEFT },
+ { 0x43, KEY_RIGHT },
+ { 0x0b, KEY_ENTER },
+
+ { 0x10, KEY_CHANNELUP },
+ { 0x11, KEY_CHANNELDOWN },
+
+ { 0x13, KEY_VOLUMEUP },
+ { 0x12, KEY_VOLUMEDOWN },
+
+ { 0x19, KEY_TIME}, /* Timeshift */
+ { 0x1a, KEY_STOP},
+ { 0x1b, KEY_RECORD},
+ { 0x4b, KEY_EMAIL},
+
+ { 0x40, KEY_REWIND},
+ { 0x44, KEY_PLAYPAUSE},
+ { 0x41, KEY_FORWARD},
+ { 0x22, KEY_TEXT},
+
+ { 0x15, KEY_AUDIO}, /* ((*)) */
+ { 0x0f, KEY_MODE}, /* display ratio */
+ { 0x1c, KEY_SYSRQ}, /* snapshot */
+ { 0x4a, KEY_SLEEP}, /* sleep timer */
+
+ { 0x48, KEY_SOUND}, /* switch theater mode */
+ { 0x49, KEY_BLUE}, /* A */
+ { 0x18, KEY_RED}, /* B */
+ { 0x23, KEY_GREEN}, /* C */
+};
+
+static struct rc_map_list kworld_pc150u_map = {
+ .map = {
+ .scan = kworld_pc150u,
+ .size = ARRAY_SIZE(kworld_pc150u),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_KWORLD_PC150U,
+ }
+};
+
+static int __init init_rc_map_kworld_pc150u(void)
+{
+ return rc_map_register(&kworld_pc150u_map);
+}
+
+static void __exit exit_rc_map_kworld_pc150u(void)
+{
+ rc_map_unregister(&kworld_pc150u_map);
+}
+
+module_init(init_rc_map_kworld_pc150u)
+module_exit(exit_rc_map_kworld_pc150u)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kyle Strickland <kyle@kyle.strickland.name>");
diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
index f3b86c8db679..8d4dae2e2ece 100644
--- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
+++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
@@ -18,6 +18,8 @@
*/
static struct rc_map_table nec_terratec_cinergy_xs[] = {
+
+ /* Terratec Grey IR, with most keys in orange */
{ 0x1441, KEY_HOME},
{ 0x1401, KEY_POWER2},
@@ -78,6 +80,56 @@ static struct rc_map_table nec_terratec_cinergy_xs[] = {
{ 0x144e, KEY_REWIND},
{ 0x144f, KEY_FASTFORWARD},
{ 0x145c, KEY_NEXT},
+
+ /* Terratec Black IR, with most keys in black */
+ { 0x04eb01, KEY_POWER2},
+
+ { 0x04eb02, KEY_1},
+ { 0x04eb03, KEY_2},
+ { 0x04eb04, KEY_3},
+ { 0x04eb05, KEY_4},
+ { 0x04eb06, KEY_5},
+ { 0x04eb07, KEY_6},
+ { 0x04eb08, KEY_7},
+ { 0x04eb09, KEY_8},
+ { 0x04eb0a, KEY_9},
+ { 0x04eb0c, KEY_0},
+
+ { 0x04eb0b, KEY_TEXT}, /* TXT */
+ { 0x04eb0d, KEY_REFRESH}, /* Refresh */
+
+ { 0x04eb0e, KEY_HOME},
+ { 0x04eb0f, KEY_EPG},
+
+ { 0x04eb10, KEY_UP},
+ { 0x04eb11, KEY_LEFT},
+ { 0x04eb12, KEY_OK},
+ { 0x04eb13, KEY_RIGHT},
+ { 0x04eb14, KEY_DOWN},
+
+ { 0x04eb15, KEY_BACKSPACE},
+ { 0x04eb16, KEY_INFO},
+
+ { 0x04eb17, KEY_RED},
+ { 0x04eb18, KEY_GREEN},
+ { 0x04eb19, KEY_YELLOW},
+ { 0x04eb1a, KEY_BLUE},
+
+ { 0x04eb1c, KEY_VOLUMEUP},
+ { 0x04eb1e, KEY_VOLUMEDOWN},
+
+ { 0x04eb1d, KEY_MUTE},
+
+ { 0x04eb1b, KEY_CHANNELUP},
+ { 0x04eb1f, KEY_CHANNELDOWN},
+
+ { 0x04eb40, KEY_RECORD},
+ { 0x04eb4c, KEY_PLAY},
+ { 0x04eb58, KEY_PAUSE},
+
+ { 0x04eb54, KEY_REWIND},
+ { 0x04eb48, KEY_STOP},
+ { 0x04eb5c, KEY_NEXT},
};
static struct rc_map_list nec_terratec_cinergy_xs_map = {
diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c
index 3bd1de1f585c..23ee05e53949 100644
--- a/drivers/media/rc/keymaps/rc-videomate-m1f.c
+++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c
@@ -1,4 +1,4 @@
-/* videomate-m1f.h - Keytable for videomate_m1f Remote Controller
+/* videomate-k100.h - Keytable for videomate_k100 Remote Controller
*
* keymap imported from ir-keymaps.c
*
@@ -13,7 +13,7 @@
#include <media/rc-map.h>
#include <linux/module.h>
-static struct rc_map_table videomate_m1f[] = {
+static struct rc_map_table videomate_k100[] = {
{ 0x01, KEY_POWER },
{ 0x31, KEY_TUNER },
{ 0x33, KEY_VIDEO },
@@ -67,27 +67,27 @@ static struct rc_map_table videomate_m1f[] = {
{ 0x18, KEY_TEXT },
};
-static struct rc_map_list videomate_m1f_map = {
+static struct rc_map_list videomate_k100_map = {
.map = {
- .scan = videomate_m1f,
- .size = ARRAY_SIZE(videomate_m1f),
+ .scan = videomate_k100,
+ .size = ARRAY_SIZE(videomate_k100),
.rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
- .name = RC_MAP_VIDEOMATE_M1F,
+ .name = RC_MAP_VIDEOMATE_K100,
}
};
-static int __init init_rc_map_videomate_m1f(void)
+static int __init init_rc_map_videomate_k100(void)
{
- return rc_map_register(&videomate_m1f_map);
+ return rc_map_register(&videomate_k100_map);
}
-static void __exit exit_rc_map_videomate_m1f(void)
+static void __exit exit_rc_map_videomate_k100(void)
{
- rc_map_unregister(&videomate_m1f_map);
+ rc_map_unregister(&videomate_k100_map);
}
-module_init(init_rc_map_videomate_m1f)
-module_exit(exit_rc_map_videomate_m1f)
+module_init(init_rc_map_videomate_k100)
+module_exit(exit_rc_map_videomate_k100)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pavel Osnova <pvosnova@gmail.com>");
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 27997a9ceb0d..ca12d3289bfe 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -38,7 +38,7 @@
#include <media/lirc.h>
#include <media/lirc_dev.h>
-static int debug;
+static bool debug;
#define IRCTL_DEV_NAME "BaseRemoteCtl"
#define NOPLUG -1
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 20bb12d6fbbe..e150a2e29a4b 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -156,9 +156,9 @@
/* module parameters */
#ifdef CONFIG_USB_DEBUG
-static int debug = 1;
+static bool debug = 1;
#else
-static int debug;
+static bool debug;
#endif
#define mce_dbg(dev, fmt, ...) \
@@ -361,6 +361,8 @@ static struct usb_device_id mceusb_dev_table[] = {
{ USB_DEVICE(VENDOR_FORMOSA, 0xe03c) },
/* Formosa Industrial Computing */
{ USB_DEVICE(VENDOR_FORMOSA, 0xe03e) },
+ /* Formosa Industrial Computing */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe042) },
/* Fintek eHome Infrared Transceiver (HP branded) */
{ USB_DEVICE(VENDOR_FINTEK, 0x5168) },
/* Fintek eHome Infrared Transceiver */
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index c6ca870e8b7e..96f0a8bb39ea 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -35,7 +35,7 @@ struct ir_raw_event_ctrl {
struct list_head list; /* to keep track of raw clients */
struct task_struct *thread;
spinlock_t lock;
- struct kfifo kfifo; /* fifo for the pulse/space durations */
+ struct kfifo_rec_ptr_1 kfifo; /* fifo for the pulse/space durations */
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
struct rc_dev *dev; /* pointer to the parent rc_dev */
@@ -84,6 +84,11 @@ struct ir_raw_event_ctrl {
unsigned count;
unsigned wanted_bits;
} rc5_sz;
+ struct sanyo_dec {
+ int state;
+ unsigned count;
+ u64 bits;
+ } sanyo;
struct mce_kbd_dec {
struct input_dev *idev;
struct timer_list rx_timeout;
@@ -193,6 +198,13 @@ static inline void load_jvc_decode(void) { }
static inline void load_sony_decode(void) { }
#endif
+/* from ir-sanyo-decoder.c */
+#ifdef CONFIG_IR_SANYO_DECODER_MODULE
+#define load_sanyo_decode() request_module("ir-sanyo-decoder")
+#else
+static inline void load_sanyo_decode(void) { }
+#endif
+
/* from ir-mce_kbd-decoder.c */
#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE
#define load_mce_kbd_decode() request_module("ir-mce_kbd-decoder")
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index f5db8b949bc3..6e16b09c24a9 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -736,6 +736,7 @@ static struct {
{ RC_TYPE_JVC, "jvc" },
{ RC_TYPE_SONY, "sony" },
{ RC_TYPE_RC5_SZ, "rc-5-sz" },
+ { RC_TYPE_SANYO, "sanyo" },
{ RC_TYPE_MCE_KBD, "mce_kbd" },
{ RC_TYPE_LIRC, "lirc" },
{ RC_TYPE_OTHER, "other" },
@@ -1028,6 +1029,7 @@ EXPORT_SYMBOL_GPL(rc_free_device);
int rc_register_device(struct rc_dev *dev)
{
+ static bool raw_init = false; /* raw decoders loaded? */
static atomic_t devno = ATOMIC_INIT(0);
struct rc_map *rc_map;
const char *path;
@@ -1102,6 +1104,12 @@ int rc_register_device(struct rc_dev *dev)
kfree(path);
if (dev->driver_type == RC_DRIVER_IR_RAW) {
+ /* Load raw decoders, if they aren't already */
+ if (!raw_init) {
+ IR_dprintk(1, "Loading raw decoders\n");
+ ir_raw_init();
+ raw_init = true;
+ }
rc = ir_raw_event_register(dev);
if (rc < 0)
goto out_input;
@@ -1175,8 +1183,6 @@ static int __init rc_core_init(void)
return rc;
}
- /* Initialize/load the decoders/keymap code that will be used */
- ir_raw_init();
rc_map_register(&empty_map);
return 0;
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 07322fb75eff..ad95c67a4dba 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -286,12 +286,6 @@ static void redrat3_issue_async(struct redrat3_dev *rr3)
rr3_ftr(rr3->dev, "Entering %s\n", __func__);
- if (!rr3->det_enabled) {
- dev_warn(rr3->dev, "not issuing async read, "
- "detector not enabled\n");
- return;
- }
-
memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize);
res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC);
if (res)
@@ -827,6 +821,7 @@ out:
static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
{
struct redrat3_dev *rr3;
+ int ret;
if (!urb)
return;
@@ -840,15 +835,13 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
rr3_ftr(rr3->dev, "Entering %s\n", __func__);
- if (!rr3->det_enabled) {
- rr3_dbg(rr3->dev, "received a read callback but detector "
- "disabled - ignoring\n");
- return;
- }
-
switch (urb->status) {
case 0:
- redrat3_get_ir_data(rr3, urb->actual_length);
+ ret = redrat3_get_ir_data(rr3, urb->actual_length);
+ if (!ret) {
+ /* no error, prepare to read more */
+ redrat3_issue_async(rr3);
+ }
break;
case -ECONNRESET:
@@ -865,11 +858,6 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
rr3->pkttype = 0;
break;
}
-
- if (!rr3->transmitting)
- redrat3_issue_async(rr3);
- else
- rr3_dbg(rr3->dev, "IR transmit in progress\n");
}
static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
@@ -896,21 +884,24 @@ static u16 mod_freq_to_val(unsigned int mod_freq)
return (u16)(65536 - (mult / mod_freq));
}
-static int redrat3_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier)
{
- struct redrat3_dev *rr3 = dev->priv;
+ struct redrat3_dev *rr3 = rcdev->priv;
+ struct device *dev = rr3->dev;
+ rr3_dbg(dev, "Setting modulation frequency to %u", carrier);
rr3->carrier = carrier;
return carrier;
}
-static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
+static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
+ unsigned count)
{
struct redrat3_dev *rr3 = rcdev->priv;
struct device *dev = rr3->dev;
struct redrat3_signal_header header;
- int i, j, count, ret, ret_len, offset;
+ int i, j, ret, ret_len, offset;
int lencheck, cur_sample_len, pipe;
char *buffer = NULL, *sigdata = NULL;
int *sample_lens = NULL;
@@ -928,20 +919,13 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
return -EAGAIN;
}
- count = n / sizeof(int);
if (count > (RR3_DRIVER_MAXLENS * 2))
return -EINVAL;
+ /* rr3 will disable rc detector on transmit */
+ rr3->det_enabled = false;
rr3->transmitting = true;
- redrat3_disable_detector(rr3);
-
- if (rr3->det_enabled) {
- dev_err(dev, "%s: cannot tx while rx is enabled\n", __func__);
- ret = -EIO;
- goto out;
- }
-
sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL);
if (!sample_lens) {
ret = -ENOMEM;
@@ -1055,7 +1039,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
if (ret < 0)
dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
else
- ret = n;
+ ret = count;
out:
kfree(sample_lens);
@@ -1063,8 +1047,8 @@ out:
kfree(sigdata);
rr3->transmitting = false;
-
- redrat3_enable_detector(rr3);
+ /* rr3 re-enables rc detector because it was enabled before */
+ rr3->det_enabled = true;
return ret;
}
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index b1d29d09eeae..d6f4bfe09391 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -43,9 +43,9 @@
#define DRIVER_DESC "Streamzap Remote Control driver"
#ifdef CONFIG_USB_DEBUG
-static int debug = 1;
+static bool debug = 1;
#else
-static int debug;
+static bool debug;
#endif
#define USB_STREAMZAP_VENDOR_ID 0x0e9c
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index e7f7a57bf684..b09c5fae489b 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -226,11 +226,11 @@ module_param(protocol, uint, 0444);
MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command "
"(0 = RC5, 1 = NEC, 2 = RC6A, default)");
-static int invert; /* default = 0 */
+static bool invert; /* default = 0 */
module_param(invert, bool, 0444);
MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver");
-static int txandrx; /* default = 0 */
+static bool txandrx; /* default = 0 */
module_param(txandrx, bool, 0444);
MODULE_PARM_DESC(invert, "Allow simultaneous TX and RX");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index b303a3f8a9f8..f2479c5c0eb2 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -273,6 +273,16 @@ config VIDEO_ADV7180
To compile this driver as a module, choose M here: the
module will be called adv7180.
+config VIDEO_ADV7183
+ tristate "Analog Devices ADV7183 decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ V4l2 subdevice driver for the Analog Devices
+ ADV7183 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adv7183.
+
config VIDEO_BT819
tristate "BT819A VideoStream decoder"
depends on VIDEO_V4L2 && I2C
@@ -459,6 +469,9 @@ config VIDEO_AK881X
comment "Camera sensor devices"
+config VIDEO_APTINA_PLL
+ tristate
+
config VIDEO_OV7670
tristate "OmniVision OV7670 sensor support"
depends on I2C && VIDEO_V4L2
@@ -467,9 +480,28 @@ config VIDEO_OV7670
OV7670 VGA camera. It currently only works with the M88ALP01
controller.
+config VIDEO_VS6624
+ tristate "ST VS6624 sensor support"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the ST VS6624
+ camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vs6624.
+
+config VIDEO_MT9M032
+ tristate "MT9M032 camera sensor support"
+ depends on I2C && VIDEO_V4L2
+ select VIDEO_APTINA_PLL
+ ---help---
+ This driver supports MT9M032 camera sensors from Aptina, monochrome
+ models only.
+
config VIDEO_MT9P031
tristate "Aptina MT9P031 support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ select VIDEO_APTINA_PLL
---help---
This is a Video4Linux2 sensor-level driver for the Aptina
(Micron) mt9p031 5 Mpixel camera.
@@ -533,6 +565,13 @@ config VIDEO_ADP1653
This is a driver for the ADP1653 flash controller. It is used for
example in Nokia N900.
+config VIDEO_AS3645A
+ tristate "AS3645A flash driver support"
+ depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+ ---help---
+ This is a driver for the AS3645A and LM3555 flash controllers. It has
+ build in control for flash, torch and indicator LEDs.
+
comment "Video improvement chips"
config VIDEO_UPD64031A
@@ -580,25 +619,6 @@ config VIDEO_M52790
endmenu # encoder / decoder chips
-config VIDEO_SH_VOU
- tristate "SuperH VOU video output driver"
- depends on VIDEO_DEV && ARCH_SHMOBILE
- select VIDEOBUF_DMA_CONTIG
- help
- Support for the Video Output Unit (VOU) on SuperH SoCs.
-
-config VIDEO_VIU
- tristate "Freescale VIU Video Driver"
- depends on VIDEO_V4L2 && PPC_MPC512x
- select VIDEOBUF_DMA_CONTIG
- default y
- ---help---
- Support for Freescale VIU video driver. This device captures
- video data, or overlays video on DIU frame buffer.
-
- Say Y here if you want to enable VIU device on MPC5121e Rev2+.
- In doubt, say N.
-
config VIDEO_VIVI
tristate "Virtual Video Driver"
depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
@@ -613,66 +633,130 @@ config VIDEO_VIVI
Say Y here if you want to test video apps or debug V4L devices.
In doubt, say N.
-source "drivers/media/video/davinci/Kconfig"
+#
+# USB Multimedia device configuration
+#
-source "drivers/media/video/omap/Kconfig"
+menuconfig V4L_USB_DRIVERS
+ bool "V4L USB devices"
+ depends on USB
+ default y
-source "drivers/media/video/bt8xx/Kconfig"
+if V4L_USB_DRIVERS
-config VIDEO_PMS
- tristate "Mediavision Pro Movie Studio Video For Linux"
- depends on ISA && VIDEO_V4L2
- help
- Say Y if you have such a thing.
+source "drivers/media/video/uvc/Kconfig"
+
+source "drivers/media/video/gspca/Kconfig"
+
+source "drivers/media/video/pvrusb2/Kconfig"
+
+source "drivers/media/video/hdpvr/Kconfig"
+
+source "drivers/media/video/em28xx/Kconfig"
+
+source "drivers/media/video/tlg2300/Kconfig"
+
+source "drivers/media/video/cx231xx/Kconfig"
+
+source "drivers/media/video/tm6000/Kconfig"
+
+source "drivers/media/video/usbvision/Kconfig"
+
+source "drivers/media/video/et61x251/Kconfig"
+
+source "drivers/media/video/sn9c102/Kconfig"
+
+source "drivers/media/video/pwc/Kconfig"
+
+source "drivers/media/video/cpia2/Kconfig"
+
+config USB_ZR364XX
+ tristate "USB ZR364XX Camera support"
+ depends on VIDEO_V4L2
+ select VIDEOBUF_GEN
+ select VIDEOBUF_VMALLOC
+ ---help---
+ Say Y here if you want to connect this type of camera to your
+ computer's USB port.
+ See <file:Documentation/video4linux/zr364xx.txt> for more info
+ and list of supported cameras.
To compile this driver as a module, choose M here: the
- module will be called pms.
+ module will be called zr364xx.
-config VIDEO_BWQCAM
- tristate "Quickcam BW Video For Linux"
- depends on PARPORT && VIDEO_V4L2
- help
- Say Y have if you the black and white version of the QuickCam
- camera. See the next option for the color version.
+config USB_STKWEBCAM
+ tristate "USB Syntek DC1125 Camera support"
+ depends on VIDEO_V4L2 && EXPERIMENTAL
+ ---help---
+ Say Y here if you want to use this type of camera.
+ Supported devices are typically found in some Asus laptops,
+ with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
+ may be supported by the stk11xx driver, from which this is
+ derived, see <http://sourceforge.net/projects/syntekdriver/>
To compile this driver as a module, choose M here: the
- module will be called bw-qcam.
+ module will be called stkwebcam.
-config VIDEO_CQCAM
- tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2
+config USB_S2255
+ tristate "USB Sensoray 2255 video capture device"
+ depends on VIDEO_V4L2
+ select VIDEOBUF_VMALLOC
+ default n
help
- This is the video4linux driver for the colour version of the
- Connectix QuickCam. If you have one of these cameras, say Y here,
- otherwise say N. This driver does not work with the original
- monochrome QuickCam, QuickCam VC or QuickClip. It is also available
- as a module (c-qcam).
- Read <file:Documentation/video4linux/CQcam.txt> for more information.
+ Say Y here if you want support for the Sensoray 2255 USB device.
+ This driver can be compiled as a module, called s2255drv.
-config VIDEO_W9966
- tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux"
- depends on PARPORT_1284 && PARPORT && VIDEO_V4L2
- help
- Video4linux driver for Winbond's w9966 based Webcams.
- Currently tested with the LifeView FlyCam Supra.
- If you have one of these cameras, say Y here
- otherwise say N.
- This driver is also available as a module (w9966).
+endif # V4L_USB_DRIVERS
- Check out <file:Documentation/video4linux/w9966.txt> for more
- information.
+#
+# PCI drivers configuration
+#
-source "drivers/media/video/cpia2/Kconfig"
+menuconfig V4L_PCI_DRIVERS
+ bool "V4L PCI(e) devices"
+ depends on PCI
+ default y
+ ---help---
+ Say Y here to enable support for these PCI(e) drivers.
-config VIDEO_VINO
- tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
- depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
- select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
- help
- Say Y here to build in support for the Vino video input system found
- on SGI Indy machines.
+if V4L_PCI_DRIVERS
-source "drivers/media/video/zoran/Kconfig"
+source "drivers/media/video/au0828/Kconfig"
+
+source "drivers/media/video/bt8xx/Kconfig"
+
+source "drivers/media/video/cx18/Kconfig"
+
+source "drivers/media/video/cx23885/Kconfig"
+
+source "drivers/media/video/cx25821/Kconfig"
+
+source "drivers/media/video/cx88/Kconfig"
+
+config VIDEO_HEXIUM_GEMINI
+ tristate "Hexium Gemini frame grabber"
+ depends on PCI && VIDEO_V4L2 && I2C
+ select VIDEO_SAA7146_VV
+ ---help---
+ This is a video4linux driver for the Hexium Gemini frame
+ grabber card by Hexium. Please note that the Gemini Dual
+ card is *not* fully supported.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hexium_gemini.
+
+config VIDEO_HEXIUM_ORION
+ tristate "Hexium HV-PCI6 and Orion frame grabber"
+ depends on PCI && VIDEO_V4L2 && I2C
+ select VIDEO_SAA7146_VV
+ ---help---
+ This is a video4linux driver for the Hexium HV-PCI6 and
+ Orion frame grabber cards by Hexium.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hexium_orion.
+
+source "drivers/media/video/ivtv/Kconfig"
config VIDEO_MEYE
tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
@@ -688,8 +772,6 @@ config VIDEO_MEYE
To compile this driver as a module, choose M here: the
module will be called meye.
-source "drivers/media/video/saa7134/Kconfig"
-
config VIDEO_MXB
tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
depends on PCI && VIDEO_V4L2 && I2C
@@ -706,28 +788,121 @@ config VIDEO_MXB
To compile this driver as a module, choose M here: the
module will be called mxb.
-config VIDEO_HEXIUM_ORION
- tristate "Hexium HV-PCI6 and Orion frame grabber"
- depends on PCI && VIDEO_V4L2 && I2C
- select VIDEO_SAA7146_VV
+source "drivers/media/video/saa7134/Kconfig"
+
+source "drivers/media/video/saa7164/Kconfig"
+
+source "drivers/media/video/zoran/Kconfig"
+
+endif # V4L_PCI_DRIVERS
+
+#
+# ISA & parallel port drivers configuration
+#
+
+menuconfig V4L_ISA_PARPORT_DRIVERS
+ bool "V4L ISA and parallel port devices"
+ depends on ISA || PARPORT
+ default n
---help---
- This is a video4linux driver for the Hexium HV-PCI6 and
- Orion frame grabber cards by Hexium.
+ Say Y here to enable support for these ISA and parallel port drivers.
+
+if V4L_ISA_PARPORT_DRIVERS
+
+config VIDEO_BWQCAM
+ tristate "Quickcam BW Video For Linux"
+ depends on PARPORT && VIDEO_V4L2
+ help
+ Say Y have if you the black and white version of the QuickCam
+ camera. See the next option for the color version.
To compile this driver as a module, choose M here: the
- module will be called hexium_orion.
+ module will be called bw-qcam.
-config VIDEO_HEXIUM_GEMINI
- tristate "Hexium Gemini frame grabber"
- depends on PCI && VIDEO_V4L2 && I2C
- select VIDEO_SAA7146_VV
- ---help---
- This is a video4linux driver for the Hexium Gemini frame
- grabber card by Hexium. Please note that the Gemini Dual
- card is *not* fully supported.
+config VIDEO_CQCAM
+ tristate "QuickCam Colour Video For Linux"
+ depends on PARPORT && VIDEO_V4L2
+ help
+ This is the video4linux driver for the colour version of the
+ Connectix QuickCam. If you have one of these cameras, say Y here,
+ otherwise say N. This driver does not work with the original
+ monochrome QuickCam, QuickCam VC or QuickClip. It is also available
+ as a module (c-qcam).
+ Read <file:Documentation/video4linux/CQcam.txt> for more information.
+
+config VIDEO_PMS
+ tristate "Mediavision Pro Movie Studio Video For Linux"
+ depends on ISA && VIDEO_V4L2
+ help
+ Say Y if you have the ISA Mediavision Pro Movie Studio
+ capture card.
To compile this driver as a module, choose M here: the
- module will be called hexium_gemini.
+ module will be called pms.
+
+config VIDEO_W9966
+ tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux"
+ depends on PARPORT_1284 && PARPORT && VIDEO_V4L2
+ help
+ Video4linux driver for Winbond's w9966 based Webcams.
+ Currently tested with the LifeView FlyCam Supra.
+ If you have one of these cameras, say Y here
+ otherwise say N.
+ This driver is also available as a module (w9966).
+
+ Check out <file:Documentation/video4linux/w9966.txt> for more
+ information.
+
+endif # V4L_ISA_PARPORT_DRIVERS
+
+menuconfig V4L_PLATFORM_DRIVERS
+ bool "V4L platform devices"
+ default n
+ ---help---
+ Say Y here to enable support for platform-specific V4L drivers.
+
+if V4L_PLATFORM_DRIVERS
+
+source "drivers/media/video/marvell-ccic/Kconfig"
+
+config VIDEO_VIA_CAMERA
+ tristate "VIAFB camera controller support"
+ depends on FB_VIA
+ select VIDEOBUF_DMA_SG
+ select VIDEO_OV7670
+ help
+ Driver support for the integrated camera controller in VIA
+ Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems
+ with ov7670 sensors.
+
+#
+# Platform multimedia device configuration
+#
+
+source "drivers/media/video/davinci/Kconfig"
+
+source "drivers/media/video/omap/Kconfig"
+
+source "drivers/media/video/blackfin/Kconfig"
+
+config VIDEO_SH_VOU
+ tristate "SuperH VOU video output driver"
+ depends on VIDEO_DEV && ARCH_SHMOBILE
+ select VIDEOBUF_DMA_CONTIG
+ help
+ Support for the Video Output Unit (VOU) on SuperH SoCs.
+
+config VIDEO_VIU
+ tristate "Freescale VIU Video Driver"
+ depends on VIDEO_V4L2 && PPC_MPC512x
+ select VIDEOBUF_DMA_CONTIG
+ default y
+ ---help---
+ Support for Freescale VIU video driver. This device captures
+ video data, or overlays video on DIU frame buffer.
+
+ Say Y here if you want to enable VIU device on MPC5121e Rev2+.
+ In doubt, say N.
config VIDEO_TIMBERDALE
tristate "Support for timberdale Video In/LogiWIN"
@@ -739,21 +914,13 @@ config VIDEO_TIMBERDALE
---help---
Add support for the Video In peripherial of the timberdale FPGA.
-source "drivers/media/video/cx88/Kconfig"
-
-source "drivers/media/video/cx23885/Kconfig"
-
-source "drivers/media/video/cx25821/Kconfig"
-
-source "drivers/media/video/au0828/Kconfig"
-
-source "drivers/media/video/ivtv/Kconfig"
-
-source "drivers/media/video/cx18/Kconfig"
-
-source "drivers/media/video/saa7164/Kconfig"
-
-source "drivers/media/video/marvell-ccic/Kconfig"
+config VIDEO_VINO
+ tristate "SGI Vino Video For Linux"
+ depends on I2C && SGI_IP22 && VIDEO_V4L2
+ select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
+ help
+ Say Y here to build in support for the Vino video input system found
+ on SGI Indy machines.
config VIDEO_M32R_AR
tristate "AR devices"
@@ -774,16 +941,6 @@ config VIDEO_M32R_AR_M64278
To compile this driver as a module, choose M here: the
module will be called arv.
-config VIDEO_VIA_CAMERA
- tristate "VIAFB camera controller support"
- depends on FB_VIA
- select VIDEOBUF_DMA_SG
- select VIDEO_OV7670
- help
- Driver support for the integrated camera controller in VIA
- Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems
- with ov7670 sensors.
-
config VIDEO_OMAP3
tristate "OMAP 3 Camera support (EXPERIMENTAL)"
depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL
@@ -964,7 +1121,7 @@ config VIDEO_MX2_HOSTSUPPORT
config VIDEO_MX2
tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25)
- select VIDEOBUF_DMA_CONTIG
+ select VIDEOBUF2_DMA_CONTIG
select VIDEO_MX2_HOSTSUPPORT
---help---
This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
@@ -993,7 +1150,8 @@ config VIDEO_ATMEL_ISI
config VIDEO_S5P_MIPI_CSIS
tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
- depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API
+ depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P
+ depends on VIDEO_V4L2_SUBDEV_API && REGULATOR
---help---
This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
@@ -1002,78 +1160,7 @@ config VIDEO_S5P_MIPI_CSIS
source "drivers/media/video/s5p-tv/Kconfig"
-#
-# USB Multimedia device configuration
-#
-
-menuconfig V4L_USB_DRIVERS
- bool "V4L USB devices"
- depends on USB
- default y
-
-if V4L_USB_DRIVERS && USB
-
-source "drivers/media/video/uvc/Kconfig"
-
-source "drivers/media/video/gspca/Kconfig"
-
-source "drivers/media/video/pvrusb2/Kconfig"
-
-source "drivers/media/video/hdpvr/Kconfig"
-
-source "drivers/media/video/em28xx/Kconfig"
-
-source "drivers/media/video/tlg2300/Kconfig"
-
-source "drivers/media/video/cx231xx/Kconfig"
-
-source "drivers/media/video/tm6000/Kconfig"
-
-source "drivers/media/video/usbvision/Kconfig"
-
-source "drivers/media/video/et61x251/Kconfig"
-
-source "drivers/media/video/sn9c102/Kconfig"
-
-source "drivers/media/video/pwc/Kconfig"
-
-config USB_ZR364XX
- tristate "USB ZR364XX Camera support"
- depends on VIDEO_V4L2
- select VIDEOBUF_GEN
- select VIDEOBUF_VMALLOC
- ---help---
- Say Y here if you want to connect this type of camera to your
- computer's USB port.
- See <file:Documentation/video4linux/zr364xx.txt> for more info
- and list of supported cameras.
-
- To compile this driver as a module, choose M here: the
- module will be called zr364xx.
-
-config USB_STKWEBCAM
- tristate "USB Syntek DC1125 Camera support"
- depends on VIDEO_V4L2 && EXPERIMENTAL
- ---help---
- Say Y here if you want to use this type of camera.
- Supported devices are typically found in some Asus laptops,
- with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
- may be supported by the stk11xx driver, from which this is
- derived, see <http://sourceforge.net/projects/syntekdriver/>
-
- To compile this driver as a module, choose M here: the
- module will be called stkwebcam.
-
-config USB_S2255
- tristate "USB Sensoray 2255 video capture device"
- depends on VIDEO_V4L2
- select VIDEOBUF_VMALLOC
- default n
- help
- Say Y here if you want support for the Sensoray 2255 USB device.
- This driver can be compiled as a module, called s2255drv.
-
-endif # V4L_USB_DRIVERS
+endif # V4L_PLATFORM_DRIVERS
endif # VIDEO_CAPTURE_DRIVERS
menuconfig V4L_MEM2MEM_DRIVERS
@@ -1098,6 +1185,23 @@ config VIDEO_MEM2MEM_TESTDEV
This is a virtual test device for the memory-to-memory driver
framework.
+config VIDEO_SAMSUNG_S5P_G2D
+ tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ default n
+ ---help---
+ This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D
+ 2d graphics accelerator.
+
+config VIDEO_SAMSUNG_S5P_JPEG
+ tristate "Samsung S5P/Exynos4 JPEG codec driver (EXPERIMENTAL)"
+ depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P && EXPERIMENTAL
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ ---help---
+ This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec
config VIDEO_SAMSUNG_S5P_MFC
tristate "Samsung S5P MFC 5.1 Video Codec"
@@ -1107,4 +1211,14 @@ config VIDEO_SAMSUNG_S5P_MFC
help
MFC 5.1 driver for V4L2.
+config VIDEO_MX2_EMMAPRP
+ tristate "MX2 eMMa-PrP support"
+ depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ help
+ MX2X chips have a PrP that can be used to process buffers from
+ memory to memory. Operations include resizing and format
+ conversion.
+
endif # V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 117f9c4b4cb9..a6282a3a6a82 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -12,16 +12,19 @@ omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
+ifeq ($(CONFIG_COMPAT),y)
+ videodev-objs += v4l2-compat-ioctl32.o
+endif
# V4L2 core modules
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
-ifeq ($(CONFIG_COMPAT),y)
- obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
-endif
-
obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
+# Helper modules
+
+obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o
+
# All i2c modules must come first:
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
@@ -40,8 +43,10 @@ obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o
+obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o
obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
+obj-$(CONFIG_VIDEO_VS6624) += vs6624.o
obj-$(CONFIG_VIDEO_BT819) += bt819.o
obj-$(CONFIG_VIDEO_BT856) += bt856.o
obj-$(CONFIG_VIDEO_BT866) += bt866.o
@@ -65,6 +70,7 @@ 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_MT9M032) += mt9m032.o
obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
@@ -74,6 +80,7 @@ obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/
obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o
obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
+obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o
obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
@@ -176,10 +183,17 @@ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
+obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
+
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/
+
+obj-$(CONFIG_BLACKFIN) += blackfin/
+
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o
@@ -195,6 +209,6 @@ obj-y += davinci/
obj-$(CONFIG_ARCH_OMAP) += omap/
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
-ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c
index 12eedf4d515a..5b045b4a66fe 100644
--- a/drivers/media/video/adp1653.c
+++ b/drivers/media/video/adp1653.c
@@ -33,7 +33,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/i2c.h>
-#include <linux/module.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <media/adp1653.h>
@@ -482,24 +481,7 @@ static struct i2c_driver adp1653_i2c_driver = {
.id_table = adp1653_id_table,
};
-static int __init adp1653_init(void)
-{
- int rval;
-
- rval = i2c_add_driver(&adp1653_i2c_driver);
- if (rval)
- printk(KERN_ALERT "%s: failed at i2c_add_driver\n", __func__);
-
- return rval;
-}
-
-static void __exit adp1653_exit(void)
-{
- i2c_del_driver(&adp1653_i2c_driver);
-}
-
-module_init(adp1653_init);
-module_exit(adp1653_exit);
+module_i2c_driver(adp1653_i2c_driver);
MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver");
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 23ba5c37c3e4..6bc01fb98ff8 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -64,6 +64,11 @@ static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
static char *inputs[] = { "pass_through", "play_back" };
+static enum v4l2_mbus_pixelcode adv7170_codes[] = {
+ V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_UYVY8_1X16,
+};
+
/* ----------------------------------------------------------------------- */
static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value)
@@ -258,6 +263,60 @@ static int adv7170_s_routing(struct v4l2_subdev *sd,
return 0;
}
+static int adv7170_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(adv7170_codes))
+ return -EINVAL;
+
+ *code = adv7170_codes[index];
+ return 0;
+}
+
+static int adv7170_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ u8 val = adv7170_read(sd, 0x7);
+
+ if ((val & 0x40) == (1 << 6))
+ mf->code = V4L2_MBUS_FMT_UYVY8_1X16;
+ else
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+
+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ mf->width = 0;
+ mf->height = 0;
+ mf->field = V4L2_FIELD_ANY;
+
+ return 0;
+}
+
+static int adv7170_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ u8 val = adv7170_read(sd, 0x7);
+ int ret;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ val &= ~0x40;
+ break;
+
+ case V4L2_MBUS_FMT_UYVY8_1X16:
+ val |= 0x40;
+ break;
+
+ default:
+ v4l2_dbg(1, debug, sd,
+ "illegal v4l2_mbus_framefmt code: %d\n", mf->code);
+ return -EINVAL;
+ }
+
+ ret = adv7170_write(sd, 0x7, val);
+
+ return ret;
+}
+
static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -274,6 +333,9 @@ static const struct v4l2_subdev_core_ops adv7170_core_ops = {
static const struct v4l2_subdev_video_ops adv7170_video_ops = {
.s_std_output = adv7170_s_std_output,
.s_routing = adv7170_s_routing,
+ .s_mbus_fmt = adv7170_s_fmt,
+ .g_mbus_fmt = adv7170_g_fmt,
+ .enum_mbus_fmt = adv7170_enum_fmt,
};
static const struct v4l2_subdev_ops adv7170_ops = {
@@ -345,15 +407,4 @@ static struct i2c_driver adv7170_driver = {
.id_table = adv7170_id,
};
-static __init int init_adv7170(void)
-{
- return i2c_add_driver(&adv7170_driver);
-}
-
-static __exit void exit_adv7170(void)
-{
- i2c_del_driver(&adv7170_driver);
-}
-
-module_init(init_adv7170);
-module_exit(exit_adv7170);
+module_i2c_driver(adv7170_driver);
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 206078eca853..c7640fab5730 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -457,15 +457,4 @@ static struct i2c_driver adv7175_driver = {
.id_table = adv7175_id,
};
-static __init int init_adv7175(void)
-{
- return i2c_add_driver(&adv7175_driver);
-}
-
-static __exit void exit_adv7175(void)
-{
- i2c_del_driver(&adv7175_driver);
-}
-
-module_init(init_adv7175);
-module_exit(exit_adv7175);
+module_i2c_driver(adv7175_driver);
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c
index d2138d06bcad..b8b6c4b0cad4 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/video/adv7180.c
@@ -444,20 +444,8 @@ static struct i2c_driver adv7180_driver = {
.id_table = adv7180_id,
};
-static __init int adv7180_init(void)
-{
- return i2c_add_driver(&adv7180_driver);
-}
-
-static __exit void adv7180_exit(void)
-{
- i2c_del_driver(&adv7180_driver);
-}
-
-module_init(adv7180_init);
-module_exit(adv7180_exit);
+module_i2c_driver(adv7180_driver);
MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
MODULE_AUTHOR("Mocean Laboratories");
MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/media/video/adv7183.c b/drivers/media/video/adv7183.c
new file mode 100644
index 000000000000..e1d4c89d7140
--- /dev/null
+++ b/drivers/media/video/adv7183.c
@@ -0,0 +1,699 @@
+/*
+ * adv7183.c Analog Devices ADV7183 video decoder driver
+ *
+ * Copyright (c) 2011 Analog Devices 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.
+ *
+ * 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/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/adv7183.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#include "adv7183_regs.h"
+
+struct adv7183 {
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+
+ v4l2_std_id std; /* Current set standard */
+ u32 input;
+ u32 output;
+ unsigned reset_pin;
+ unsigned oe_pin;
+ struct v4l2_mbus_framefmt fmt;
+};
+
+/* EXAMPLES USING 27 MHz CLOCK
+ * Mode 1 CVBS Input (Composite Video on AIN5)
+ * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8.
+ */
+static const unsigned char adv7183_init_regs[] = {
+ ADV7183_IN_CTRL, 0x04, /* CVBS input on AIN5 */
+ ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */
+ ADV7183_SHAP_FILT_CTRL, 0x41, /* Set CSFM to SH1 */
+ ADV7183_ADC_CTRL, 0x16, /* Power down ADC 1 and ADC 2 */
+ ADV7183_CTI_DNR_CTRL_4, 0x04, /* Set DNR threshold to 4 for flat response */
+ /* ADI recommended programming sequence */
+ ADV7183_ADI_CTRL, 0x80,
+ ADV7183_CTI_DNR_CTRL_4, 0x20,
+ 0x52, 0x18,
+ 0x58, 0xED,
+ 0x77, 0xC5,
+ 0x7C, 0x93,
+ 0x7D, 0x00,
+ 0xD0, 0x48,
+ 0xD5, 0xA0,
+ 0xD7, 0xEA,
+ ADV7183_SD_SATURATION_CR, 0x3E,
+ ADV7183_PAL_V_END, 0x3E,
+ ADV7183_PAL_F_TOGGLE, 0x0F,
+ ADV7183_ADI_CTRL, 0x00,
+};
+
+static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct adv7183, sd);
+}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct adv7183, hdl)->sd;
+}
+
+static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg,
+ unsigned char value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int adv7183_writeregs(struct v4l2_subdev *sd,
+ const unsigned char *regs, unsigned int num)
+{
+ unsigned char reg, data;
+ unsigned int cnt = 0;
+
+ if (num & 0x1) {
+ v4l2_err(sd, "invalid regs array\n");
+ return -1;
+ }
+
+ while (cnt < num) {
+ reg = *regs++;
+ data = *regs++;
+ cnt += 2;
+
+ adv7183_write(sd, reg, data);
+ }
+ return 0;
+}
+
+static int adv7183_log_status(struct v4l2_subdev *sd)
+{
+ struct adv7183 *decoder = to_adv7183(sd);
+
+ v4l2_info(sd, "adv7183: Input control = 0x%02x\n",
+ adv7183_read(sd, ADV7183_IN_CTRL));
+ v4l2_info(sd, "adv7183: Video selection = 0x%02x\n",
+ adv7183_read(sd, ADV7183_VD_SEL));
+ v4l2_info(sd, "adv7183: Output control = 0x%02x\n",
+ adv7183_read(sd, ADV7183_OUT_CTRL));
+ v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n",
+ adv7183_read(sd, ADV7183_EXT_OUT_CTRL));
+ v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n",
+ adv7183_read(sd, ADV7183_AUTO_DET_EN));
+ v4l2_info(sd, "adv7183: Contrast = 0x%02x\n",
+ adv7183_read(sd, ADV7183_CONTRAST));
+ v4l2_info(sd, "adv7183: Brightness = 0x%02x\n",
+ adv7183_read(sd, ADV7183_BRIGHTNESS));
+ v4l2_info(sd, "adv7183: Hue = 0x%02x\n",
+ adv7183_read(sd, ADV7183_HUE));
+ v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n",
+ adv7183_read(sd, ADV7183_DEF_Y));
+ v4l2_info(sd, "adv7183: Default value C = 0x%02x\n",
+ adv7183_read(sd, ADV7183_DEF_C));
+ v4l2_info(sd, "adv7183: ADI control = 0x%02x\n",
+ adv7183_read(sd, ADV7183_ADI_CTRL));
+ v4l2_info(sd, "adv7183: Power Management = 0x%02x\n",
+ adv7183_read(sd, ADV7183_POW_MANAGE));
+ v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+ adv7183_read(sd, ADV7183_STATUS_1),
+ adv7183_read(sd, ADV7183_STATUS_2),
+ adv7183_read(sd, ADV7183_STATUS_3));
+ v4l2_info(sd, "adv7183: Ident = 0x%02x\n",
+ adv7183_read(sd, ADV7183_IDENT));
+ v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n",
+ adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL));
+ v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n",
+ adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1));
+ v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n",
+ adv7183_read(sd, ADV7183_SHAP_FILT_CTRL),
+ adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2));
+ v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n",
+ adv7183_read(sd, ADV7183_COMB_FILT_CTRL));
+ v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n",
+ adv7183_read(sd, ADV7183_ADI_CTRL_2));
+ v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n",
+ adv7183_read(sd, ADV7183_PIX_DELAY_CTRL));
+ v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n",
+ adv7183_read(sd, ADV7183_MISC_GAIN_CTRL));
+ v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n",
+ adv7183_read(sd, ADV7183_AGC_MODE_CTRL));
+ v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n",
+ adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1),
+ adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2));
+ v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n",
+ adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1),
+ adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2));
+ v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+ adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1),
+ adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2),
+ adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3));
+ v4l2_info(sd, "adv7183: Hsync positon control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+ adv7183_read(sd, ADV7183_HS_POS_CTRL_1),
+ adv7183_read(sd, ADV7183_HS_POS_CTRL_2),
+ adv7183_read(sd, ADV7183_HS_POS_CTRL_3));
+ v4l2_info(sd, "adv7183: Polarity = 0x%02x\n",
+ adv7183_read(sd, ADV7183_POLARITY));
+ v4l2_info(sd, "adv7183: ADC control = 0x%02x\n",
+ adv7183_read(sd, ADV7183_ADC_CTRL));
+ v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n",
+ adv7183_read(sd, ADV7183_SD_OFFSET_CB),
+ adv7183_read(sd, ADV7183_SD_OFFSET_CR));
+ v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n",
+ adv7183_read(sd, ADV7183_SD_SATURATION_CB),
+ adv7183_read(sd, ADV7183_SD_SATURATION_CR));
+ v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n",
+ adv7183_read(sd, ADV7183_DRIVE_STR));
+ v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name);
+ return 0;
+}
+
+static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct adv7183 *decoder = to_adv7183(sd);
+
+ *std = decoder->std;
+ return 0;
+}
+
+static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct adv7183 *decoder = to_adv7183(sd);
+ int reg;
+
+ reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
+ if (std == V4L2_STD_PAL_60)
+ reg |= 0x60;
+ else if (std == V4L2_STD_NTSC_443)
+ reg |= 0x70;
+ else if (std == V4L2_STD_PAL_N)
+ reg |= 0x90;
+ else if (std == V4L2_STD_PAL_M)
+ reg |= 0xA0;
+ else if (std == V4L2_STD_PAL_Nc)
+ reg |= 0xC0;
+ else if (std & V4L2_STD_PAL)
+ reg |= 0x80;
+ else if (std & V4L2_STD_NTSC)
+ reg |= 0x50;
+ else if (std & V4L2_STD_SECAM)
+ reg |= 0xE0;
+ else
+ return -EINVAL;
+ adv7183_write(sd, ADV7183_IN_CTRL, reg);
+
+ decoder->std = std;
+
+ return 0;
+}
+
+static int adv7183_reset(struct v4l2_subdev *sd, u32 val)
+{
+ int reg;
+
+ reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80;
+ adv7183_write(sd, ADV7183_POW_MANAGE, reg);
+ /* wait 5ms before any further i2c writes are performed */
+ usleep_range(5000, 10000);
+ return 0;
+}
+
+static int adv7183_s_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
+{
+ struct adv7183 *decoder = to_adv7183(sd);
+ int reg;
+
+ if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT))
+ return -EINVAL;
+
+ if (input != decoder->input) {
+ decoder->input = input;
+ reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0;
+ switch (input) {
+ case ADV7183_COMPOSITE1:
+ reg |= 0x1;
+ break;
+ case ADV7183_COMPOSITE2:
+ reg |= 0x2;
+ break;
+ case ADV7183_COMPOSITE3:
+ reg |= 0x3;
+ break;
+ case ADV7183_COMPOSITE4:
+ reg |= 0x4;
+ break;
+ case ADV7183_COMPOSITE5:
+ reg |= 0x5;
+ break;
+ case ADV7183_COMPOSITE6:
+ reg |= 0xB;
+ break;
+ case ADV7183_COMPOSITE7:
+ reg |= 0xC;
+ break;
+ case ADV7183_COMPOSITE8:
+ reg |= 0xD;
+ break;
+ case ADV7183_COMPOSITE9:
+ reg |= 0xE;
+ break;
+ case ADV7183_COMPOSITE10:
+ reg |= 0xF;
+ break;
+ case ADV7183_SVIDEO0:
+ reg |= 0x6;
+ break;
+ case ADV7183_SVIDEO1:
+ reg |= 0x7;
+ break;
+ case ADV7183_SVIDEO2:
+ reg |= 0x8;
+ break;
+ case ADV7183_COMPONENT0:
+ reg |= 0x9;
+ break;
+ case ADV7183_COMPONENT1:
+ reg |= 0xA;
+ break;
+ default:
+ break;
+ }
+ adv7183_write(sd, ADV7183_IN_CTRL, reg);
+ }
+
+ if (output != decoder->output) {
+ decoder->output = output;
+ reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0;
+ switch (output) {
+ case ADV7183_16BIT_OUT:
+ reg |= 0x9;
+ break;
+ default:
+ reg |= 0xC;
+ break;
+ }
+ adv7183_write(sd, ADV7183_OUT_CTRL, reg);
+ }
+
+ return 0;
+}
+
+static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ int val = ctrl->val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (val < 0)
+ val = 127 - val;
+ adv7183_write(sd, ADV7183_BRIGHTNESS, val);
+ break;
+ case V4L2_CID_CONTRAST:
+ adv7183_write(sd, ADV7183_CONTRAST, val);
+ break;
+ case V4L2_CID_SATURATION:
+ adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8);
+ adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF));
+ break;
+ case V4L2_CID_HUE:
+ adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8);
+ adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct adv7183 *decoder = to_adv7183(sd);
+ int reg;
+
+ /* enable autodetection block */
+ reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
+ adv7183_write(sd, ADV7183_IN_CTRL, reg);
+
+ /* wait autodetection switch */
+ mdelay(10);
+
+ /* get autodetection result */
+ reg = adv7183_read(sd, ADV7183_STATUS_1);
+ switch ((reg >> 0x4) & 0x7) {
+ case 0:
+ *std = V4L2_STD_NTSC;
+ break;
+ case 1:
+ *std = V4L2_STD_NTSC_443;
+ break;
+ case 2:
+ *std = V4L2_STD_PAL_M;
+ break;
+ case 3:
+ *std = V4L2_STD_PAL_60;
+ break;
+ case 4:
+ *std = V4L2_STD_PAL;
+ break;
+ case 5:
+ *std = V4L2_STD_SECAM;
+ break;
+ case 6:
+ *std = V4L2_STD_PAL_Nc;
+ break;
+ case 7:
+ *std = V4L2_STD_SECAM;
+ break;
+ default:
+ *std = V4L2_STD_UNKNOWN;
+ break;
+ }
+
+ /* after std detection, write back user set std */
+ adv7183_s_std(sd, decoder->std);
+ return 0;
+}
+
+static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+ int reg;
+
+ *status = V4L2_IN_ST_NO_SIGNAL;
+ reg = adv7183_read(sd, ADV7183_STATUS_1);
+ if (reg < 0)
+ return reg;
+ if (reg & 0x1)
+ *status = 0;
+ return 0;
+}
+
+static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index > 0)
+ return -EINVAL;
+
+ *code = V4L2_MBUS_FMT_UYVY8_2X8;
+ return 0;
+}
+
+static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct adv7183 *decoder = to_adv7183(sd);
+
+ fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ if (decoder->std & V4L2_STD_525_60) {
+ fmt->field = V4L2_FIELD_SEQ_TB;
+ fmt->width = 720;
+ fmt->height = 480;
+ } else {
+ fmt->field = V4L2_FIELD_SEQ_BT;
+ fmt->width = 720;
+ fmt->height = 576;
+ }
+ return 0;
+}
+
+static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct adv7183 *decoder = to_adv7183(sd);
+
+ adv7183_try_mbus_fmt(sd, fmt);
+ decoder->fmt = *fmt;
+ return 0;
+}
+
+static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct adv7183 *decoder = to_adv7183(sd);
+
+ *fmt = decoder->fmt;
+ return 0;
+}
+
+static int adv7183_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct adv7183 *decoder = to_adv7183(sd);
+
+ if (enable)
+ gpio_direction_output(decoder->oe_pin, 0);
+ else
+ gpio_direction_output(decoder->oe_pin, 1);
+ udelay(1);
+ return 0;
+}
+
+static int adv7183_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ int rev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ /* 0x11 for adv7183, 0x13 for adv7183b */
+ rev = adv7183_read(sd, ADV7183_IDENT);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7183, rev);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = adv7183_read(sd, reg->reg & 0xff);
+ reg->size = 1;
+ return 0;
+}
+
+static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff);
+ return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops adv7183_ctrl_ops = {
+ .s_ctrl = adv7183_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops adv7183_core_ops = {
+ .log_status = adv7183_log_status,
+ .g_std = adv7183_g_std,
+ .s_std = adv7183_s_std,
+ .reset = adv7183_reset,
+ .g_chip_ident = adv7183_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = adv7183_g_register,
+ .s_register = adv7183_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops adv7183_video_ops = {
+ .s_routing = adv7183_s_routing,
+ .querystd = adv7183_querystd,
+ .g_input_status = adv7183_g_input_status,
+ .enum_mbus_fmt = adv7183_enum_mbus_fmt,
+ .try_mbus_fmt = adv7183_try_mbus_fmt,
+ .s_mbus_fmt = adv7183_s_mbus_fmt,
+ .g_mbus_fmt = adv7183_g_mbus_fmt,
+ .s_stream = adv7183_s_stream,
+};
+
+static const struct v4l2_subdev_ops adv7183_ops = {
+ .core = &adv7183_core_ops,
+ .video = &adv7183_video_ops,
+};
+
+static int adv7183_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adv7183 *decoder;
+ struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *hdl;
+ int ret;
+ struct v4l2_mbus_framefmt fmt;
+ const unsigned *pin_array;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ pin_array = client->dev.platform_data;
+ if (pin_array == NULL)
+ return -EINVAL;
+
+ decoder = kzalloc(sizeof(struct adv7183), GFP_KERNEL);
+ if (decoder == NULL)
+ return -ENOMEM;
+
+ decoder->reset_pin = pin_array[0];
+ decoder->oe_pin = pin_array[1];
+
+ if (gpio_request(decoder->reset_pin, "ADV7183 Reset")) {
+ v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin);
+ ret = -EBUSY;
+ goto err_free_decoder;
+ }
+
+ if (gpio_request(decoder->oe_pin, "ADV7183 Output Enable")) {
+ v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin);
+ ret = -EBUSY;
+ goto err_free_reset;
+ }
+
+ sd = &decoder->sd;
+ v4l2_i2c_subdev_init(sd, client, &adv7183_ops);
+
+ hdl = &decoder->hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80);
+ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080);
+ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+ V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080);
+ /* hook the control handler into the driver */
+ sd->ctrl_handler = hdl;
+ if (hdl->error) {
+ ret = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ goto err_free_oe;
+ }
+
+ /* v4l2 doesn't support an autodetect standard, pick PAL as default */
+ decoder->std = V4L2_STD_PAL;
+ decoder->input = ADV7183_COMPOSITE4;
+ decoder->output = ADV7183_8BIT_OUT;
+
+ gpio_direction_output(decoder->oe_pin, 1);
+ /* reset chip */
+ gpio_direction_output(decoder->reset_pin, 0);
+ /* reset pulse width at least 5ms */
+ mdelay(10);
+ gpio_direction_output(decoder->reset_pin, 1);
+ /* wait 5ms before any further i2c writes are performed */
+ mdelay(5);
+
+ adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs));
+ adv7183_s_std(sd, decoder->std);
+ fmt.width = 720;
+ fmt.height = 576;
+ adv7183_s_mbus_fmt(sd, &fmt);
+
+ /* initialize the hardware to the default control values */
+ ret = v4l2_ctrl_handler_setup(hdl);
+ if (ret) {
+ v4l2_ctrl_handler_free(hdl);
+ goto err_free_oe;
+ }
+
+ return 0;
+err_free_oe:
+ gpio_free(decoder->oe_pin);
+err_free_reset:
+ gpio_free(decoder->reset_pin);
+err_free_decoder:
+ kfree(decoder);
+ return ret;
+}
+
+static int adv7183_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct adv7183 *decoder = to_adv7183(sd);
+
+ v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+ gpio_free(decoder->oe_pin);
+ gpio_free(decoder->reset_pin);
+ kfree(decoder);
+ return 0;
+}
+
+static const struct i2c_device_id adv7183_id[] = {
+ {"adv7183", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7183_id);
+
+static struct i2c_driver adv7183_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "adv7183",
+ },
+ .probe = adv7183_probe,
+ .remove = __devexit_p(adv7183_remove),
+ .id_table = adv7183_id,
+};
+
+static __init int adv7183_init(void)
+{
+ return i2c_add_driver(&adv7183_driver);
+}
+
+static __exit void adv7183_exit(void)
+{
+ i2c_del_driver(&adv7183_driver);
+}
+
+module_init(adv7183_init);
+module_exit(adv7183_exit);
+
+MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/adv7183_regs.h b/drivers/media/video/adv7183_regs.h
new file mode 100644
index 000000000000..4a5b7d211d2f
--- /dev/null
+++ b/drivers/media/video/adv7183_regs.h
@@ -0,0 +1,107 @@
+/*
+ * adv7183 - Analog Devices ADV7183 video decoder registers
+ *
+ * Copyright (c) 2011 Analog Devices 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.
+ *
+ * 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 _ADV7183_REGS_H_
+#define _ADV7183_REGS_H_
+
+#define ADV7183_IN_CTRL 0x00 /* Input control */
+#define ADV7183_VD_SEL 0x01 /* Video selection */
+#define ADV7183_OUT_CTRL 0x03 /* Output control */
+#define ADV7183_EXT_OUT_CTRL 0x04 /* Extended output control */
+#define ADV7183_AUTO_DET_EN 0x07 /* Autodetect enable */
+#define ADV7183_CONTRAST 0x08 /* Contrast */
+#define ADV7183_BRIGHTNESS 0x0A /* Brightness */
+#define ADV7183_HUE 0x0B /* Hue */
+#define ADV7183_DEF_Y 0x0C /* Default value Y */
+#define ADV7183_DEF_C 0x0D /* Default value C */
+#define ADV7183_ADI_CTRL 0x0E /* ADI control */
+#define ADV7183_POW_MANAGE 0x0F /* Power Management */
+#define ADV7183_STATUS_1 0x10 /* Status 1 */
+#define ADV7183_IDENT 0x11 /* Ident */
+#define ADV7183_STATUS_2 0x12 /* Status 2 */
+#define ADV7183_STATUS_3 0x13 /* Status 3 */
+#define ADV7183_ANAL_CLAMP_CTRL 0x14 /* Analog clamp control */
+#define ADV7183_DIGI_CLAMP_CTRL_1 0x15 /* Digital clamp control 1 */
+#define ADV7183_SHAP_FILT_CTRL 0x17 /* Shaping filter control */
+#define ADV7183_SHAP_FILT_CTRL_2 0x18 /* Shaping filter control 2 */
+#define ADV7183_COMB_FILT_CTRL 0x19 /* Comb filter control */
+#define ADV7183_ADI_CTRL_2 0x1D /* ADI control 2 */
+#define ADV7183_PIX_DELAY_CTRL 0x27 /* Pixel delay control */
+#define ADV7183_MISC_GAIN_CTRL 0x2B /* Misc gain control */
+#define ADV7183_AGC_MODE_CTRL 0x2C /* AGC mode control */
+#define ADV7183_CHRO_GAIN_CTRL_1 0x2D /* Chroma gain control 1 */
+#define ADV7183_CHRO_GAIN_CTRL_2 0x2E /* Chroma gain control 2 */
+#define ADV7183_LUMA_GAIN_CTRL_1 0x2F /* Luma gain control 1 */
+#define ADV7183_LUMA_GAIN_CTRL_2 0x30 /* Luma gain control 2 */
+#define ADV7183_VS_FIELD_CTRL_1 0x31 /* Vsync field control 1 */
+#define ADV7183_VS_FIELD_CTRL_2 0x32 /* Vsync field control 2 */
+#define ADV7183_VS_FIELD_CTRL_3 0x33 /* Vsync field control 3 */
+#define ADV7183_HS_POS_CTRL_1 0x34 /* Hsync positon control 1 */
+#define ADV7183_HS_POS_CTRL_2 0x35 /* Hsync positon control 2 */
+#define ADV7183_HS_POS_CTRL_3 0x36 /* Hsync positon control 3 */
+#define ADV7183_POLARITY 0x37 /* Polarity */
+#define ADV7183_NTSC_COMB_CTRL 0x38 /* NTSC comb control */
+#define ADV7183_PAL_COMB_CTRL 0x39 /* PAL comb control */
+#define ADV7183_ADC_CTRL 0x3A /* ADC control */
+#define ADV7183_MAN_WIN_CTRL 0x3D /* Manual window control */
+#define ADV7183_RESAMPLE_CTRL 0x41 /* Resample control */
+#define ADV7183_GEMSTAR_CTRL_1 0x48 /* Gemstar ctrl 1 */
+#define ADV7183_GEMSTAR_CTRL_2 0x49 /* Gemstar ctrl 2 */
+#define ADV7183_GEMSTAR_CTRL_3 0x4A /* Gemstar ctrl 3 */
+#define ADV7183_GEMSTAR_CTRL_4 0x4B /* Gemstar ctrl 4 */
+#define ADV7183_GEMSTAR_CTRL_5 0x4C /* Gemstar ctrl 5 */
+#define ADV7183_CTI_DNR_CTRL_1 0x4D /* CTI DNR ctrl 1 */
+#define ADV7183_CTI_DNR_CTRL_2 0x4E /* CTI DNR ctrl 2 */
+#define ADV7183_CTI_DNR_CTRL_4 0x50 /* CTI DNR ctrl 4 */
+#define ADV7183_LOCK_CNT 0x51 /* Lock count */
+#define ADV7183_FREE_LINE_LEN 0x8F /* Free-Run line length 1 */
+#define ADV7183_VBI_INFO 0x90 /* VBI info */
+#define ADV7183_WSS_1 0x91 /* WSS 1 */
+#define ADV7183_WSS_2 0x92 /* WSS 2 */
+#define ADV7183_EDTV_1 0x93 /* EDTV 1 */
+#define ADV7183_EDTV_2 0x94 /* EDTV 2 */
+#define ADV7183_EDTV_3 0x95 /* EDTV 3 */
+#define ADV7183_CGMS_1 0x96 /* CGMS 1 */
+#define ADV7183_CGMS_2 0x97 /* CGMS 2 */
+#define ADV7183_CGMS_3 0x98 /* CGMS 3 */
+#define ADV7183_CCAP_1 0x99 /* CCAP 1 */
+#define ADV7183_CCAP_2 0x9A /* CCAP 2 */
+#define ADV7183_LETTERBOX_1 0x9B /* Letterbox 1 */
+#define ADV7183_LETTERBOX_2 0x9C /* Letterbox 2 */
+#define ADV7183_LETTERBOX_3 0x9D /* Letterbox 3 */
+#define ADV7183_CRC_EN 0xB2 /* CRC enable */
+#define ADV7183_ADC_SWITCH_1 0xC3 /* ADC switch 1 */
+#define ADV7183_ADC_SWITCH_2 0xC4 /* ADC swithc 2 */
+#define ADV7183_LETTERBOX_CTRL_1 0xDC /* Letterbox control 1 */
+#define ADV7183_LETTERBOX_CTRL_2 0xDD /* Letterbox control 2 */
+#define ADV7183_SD_OFFSET_CB 0xE1 /* SD offset Cb */
+#define ADV7183_SD_OFFSET_CR 0xE2 /* SD offset Cr */
+#define ADV7183_SD_SATURATION_CB 0xE3 /* SD saturation Cb */
+#define ADV7183_SD_SATURATION_CR 0xE4 /* SD saturation Cr */
+#define ADV7183_NTSC_V_BEGIN 0xE5 /* NTSC V bit begin */
+#define ADV7183_NTSC_V_END 0xE6 /* NTSC V bit end */
+#define ADV7183_NTSC_F_TOGGLE 0xE7 /* NTSC F bit toggle */
+#define ADV7183_PAL_V_BEGIN 0xE8 /* PAL V bit begin */
+#define ADV7183_PAL_V_END 0xE9 /* PAL V bit end */
+#define ADV7183_PAL_F_TOGGLE 0xEA /* PAL F bit toggle */
+#define ADV7183_DRIVE_STR 0xF4 /* Drive strength */
+#define ADV7183_IF_COMP_CTRL 0xF8 /* IF comp control */
+#define ADV7183_VS_MODE_CTRL 0xF9 /* VS mode control */
+
+#endif
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c
index 021fab23070d..119b60401bf3 100644
--- a/drivers/media/video/adv7343.c
+++ b/drivers/media/video/adv7343.c
@@ -475,15 +475,4 @@ static struct i2c_driver adv7343_driver = {
.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);
+module_i2c_driver(adv7343_driver);
diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c
index 53c496c00fb6..ba674656b10d 100644
--- a/drivers/media/video/ak881x.c
+++ b/drivers/media/video/ak881x.c
@@ -352,18 +352,7 @@ static struct i2c_driver ak881x_i2c_driver = {
.id_table = ak881x_id,
};
-static int __init ak881x_module_init(void)
-{
- return i2c_add_driver(&ak881x_i2c_driver);
-}
-
-static void __exit ak881x_module_exit(void)
-{
- i2c_del_driver(&ak881x_i2c_driver);
-}
-
-module_init(ak881x_module_init);
-module_exit(ak881x_module_exit);
+module_i2c_driver(ak881x_i2c_driver);
MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814");
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/media/video/aptina-pll.c b/drivers/media/video/aptina-pll.c
new file mode 100644
index 000000000000..0bd3813bb59d
--- /dev/null
+++ b/drivers/media/video/aptina-pll.c
@@ -0,0 +1,174 @@
+/*
+ * Aptina Sensor PLL Configuration
+ *
+ * Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/gcd.h>
+#include <linux/kernel.h>
+#include <linux/lcm.h>
+#include <linux/module.h>
+
+#include "aptina-pll.h"
+
+int aptina_pll_calculate(struct device *dev,
+ const struct aptina_pll_limits *limits,
+ struct aptina_pll *pll)
+{
+ unsigned int mf_min;
+ unsigned int mf_max;
+ unsigned int p1_min;
+ unsigned int p1_max;
+ unsigned int p1;
+ unsigned int div;
+
+ dev_dbg(dev, "PLL: ext clock %u pix clock %u\n",
+ pll->ext_clock, pll->pix_clock);
+
+ if (pll->ext_clock < limits->ext_clock_min ||
+ pll->ext_clock > limits->ext_clock_max) {
+ dev_err(dev, "pll: invalid external clock frequency.\n");
+ return -EINVAL;
+ }
+
+ if (pll->pix_clock == 0 || pll->pix_clock > limits->pix_clock_max) {
+ dev_err(dev, "pll: invalid pixel clock frequency.\n");
+ return -EINVAL;
+ }
+
+ /* Compute the multiplier M and combined N*P1 divisor. */
+ div = gcd(pll->pix_clock, pll->ext_clock);
+ pll->m = pll->pix_clock / div;
+ div = pll->ext_clock / div;
+
+ /* We now have the smallest M and N*P1 values that will result in the
+ * desired pixel clock frequency, but they might be out of the valid
+ * range. Compute the factor by which we should multiply them given the
+ * following constraints:
+ *
+ * - minimum/maximum multiplier
+ * - minimum/maximum multiplier output clock frequency assuming the
+ * minimum/maximum N value
+ * - minimum/maximum combined N*P1 divisor
+ */
+ mf_min = DIV_ROUND_UP(limits->m_min, pll->m);
+ mf_min = max(mf_min, limits->out_clock_min /
+ (pll->ext_clock / limits->n_min * pll->m));
+ mf_min = max(mf_min, limits->n_min * limits->p1_min / div);
+ mf_max = limits->m_max / pll->m;
+ mf_max = min(mf_max, limits->out_clock_max /
+ (pll->ext_clock / limits->n_max * pll->m));
+ mf_max = min(mf_max, DIV_ROUND_UP(limits->n_max * limits->p1_max, div));
+
+ dev_dbg(dev, "pll: mf min %u max %u\n", mf_min, mf_max);
+ if (mf_min > mf_max) {
+ dev_err(dev, "pll: no valid combined N*P1 divisor.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * We're looking for the highest acceptable P1 value for which a
+ * multiplier factor MF exists that fulfills the following conditions:
+ *
+ * 1. p1 is in the [p1_min, p1_max] range given by the limits and is
+ * even
+ * 2. mf is in the [mf_min, mf_max] range computed above
+ * 3. div * mf is a multiple of p1, in order to compute
+ * n = div * mf / p1
+ * m = pll->m * mf
+ * 4. the internal clock frequency, given by ext_clock / n, is in the
+ * [int_clock_min, int_clock_max] range given by the limits
+ * 5. the output clock frequency, given by ext_clock / n * m, is in the
+ * [out_clock_min, out_clock_max] range given by the limits
+ *
+ * The first naive approach is to iterate over all p1 values acceptable
+ * according to (1) and all mf values acceptable according to (2), and
+ * stop at the first combination that fulfills (3), (4) and (5). This
+ * has a O(n^2) complexity.
+ *
+ * Instead of iterating over all mf values in the [mf_min, mf_max] range
+ * we can compute the mf increment between two acceptable values
+ * according to (3) with
+ *
+ * mf_inc = p1 / gcd(div, p1) (6)
+ *
+ * and round the minimum up to the nearest multiple of mf_inc. This will
+ * restrict the number of mf values to be checked.
+ *
+ * Furthermore, conditions (4) and (5) only restrict the range of
+ * acceptable p1 and mf values by modifying the minimum and maximum
+ * limits. (5) can be expressed as
+ *
+ * ext_clock / (div * mf / p1) * m * mf >= out_clock_min
+ * ext_clock / (div * mf / p1) * m * mf <= out_clock_max
+ *
+ * or
+ *
+ * p1 >= out_clock_min * div / (ext_clock * m) (7)
+ * p1 <= out_clock_max * div / (ext_clock * m)
+ *
+ * Similarly, (4) can be expressed as
+ *
+ * mf >= ext_clock * p1 / (int_clock_max * div) (8)
+ * mf <= ext_clock * p1 / (int_clock_min * div)
+ *
+ * We can thus iterate over the restricted p1 range defined by the
+ * combination of (1) and (7), and then compute the restricted mf range
+ * defined by the combination of (2), (6) and (8). If the resulting mf
+ * range is not empty, any value in the mf range is acceptable. We thus
+ * select the mf lwoer bound and the corresponding p1 value.
+ */
+ if (limits->p1_min == 0) {
+ dev_err(dev, "pll: P1 minimum value must be >0.\n");
+ return -EINVAL;
+ }
+
+ p1_min = max(limits->p1_min, DIV_ROUND_UP(limits->out_clock_min * div,
+ pll->ext_clock * pll->m));
+ p1_max = min(limits->p1_max, limits->out_clock_max * div /
+ (pll->ext_clock * pll->m));
+
+ for (p1 = p1_max & ~1; p1 >= p1_min; p1 -= 2) {
+ unsigned int mf_inc = p1 / gcd(div, p1);
+ unsigned int mf_high;
+ unsigned int mf_low;
+
+ mf_low = max(roundup(mf_min, mf_inc),
+ DIV_ROUND_UP(pll->ext_clock * p1,
+ limits->int_clock_max * div));
+ mf_high = min(mf_max, pll->ext_clock * p1 /
+ (limits->int_clock_min * div));
+
+ if (mf_low > mf_high)
+ continue;
+
+ pll->n = div * mf_low / p1;
+ pll->m *= mf_low;
+ pll->p1 = p1;
+ dev_dbg(dev, "PLL: N %u M %u P1 %u\n", pll->n, pll->m, pll->p1);
+ return 0;
+ }
+
+ dev_err(dev, "pll: no valid N and P1 divisors found.\n");
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(aptina_pll_calculate);
+
+MODULE_DESCRIPTION("Aptina PLL Helpers");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/aptina-pll.h b/drivers/media/video/aptina-pll.h
new file mode 100644
index 000000000000..b370e341e75d
--- /dev/null
+++ b/drivers/media/video/aptina-pll.h
@@ -0,0 +1,56 @@
+/*
+ * Aptina Sensor PLL Configuration
+ *
+ * Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __APTINA_PLL_H
+#define __APTINA_PLL_H
+
+struct aptina_pll {
+ unsigned int ext_clock;
+ unsigned int pix_clock;
+
+ unsigned int n;
+ unsigned int m;
+ unsigned int p1;
+};
+
+struct aptina_pll_limits {
+ unsigned int ext_clock_min;
+ unsigned int ext_clock_max;
+ unsigned int int_clock_min;
+ unsigned int int_clock_max;
+ unsigned int out_clock_min;
+ unsigned int out_clock_max;
+ unsigned int pix_clock_max;
+
+ unsigned int n_min;
+ unsigned int n_max;
+ unsigned int m_min;
+ unsigned int m_max;
+ unsigned int p1_min;
+ unsigned int p1_max;
+};
+
+struct device;
+
+int aptina_pll_calculate(struct device *dev,
+ const struct aptina_pll_limits *limits,
+ struct aptina_pll *pll);
+
+#endif /* __APTINA_PLL_H */
diff --git a/drivers/media/video/as3645a.c b/drivers/media/video/as3645a.c
new file mode 100644
index 000000000000..7a3371f044fc
--- /dev/null
+++ b/drivers/media/video/as3645a.c
@@ -0,0 +1,888 @@
+/*
+ * drivers/media/video/as3645a.c - AS3645A and LM3555 flash controllers driver
+ *
+ * Copyright (C) 2008-2011 Nokia Corporation
+ * Copyright (c) 2011, Intel Corporation.
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * TODO:
+ * - Check hardware FSTROBE control when sensor driver add support for this
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <media/as3645a.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#define AS_TIMER_MS_TO_CODE(t) (((t) - 100) / 50)
+#define AS_TIMER_CODE_TO_MS(c) (50 * (c) + 100)
+
+/* Register definitions */
+
+/* Read-only Design info register: Reset state: xxxx 0001 */
+#define AS_DESIGN_INFO_REG 0x00
+#define AS_DESIGN_INFO_FACTORY(x) (((x) >> 4))
+#define AS_DESIGN_INFO_MODEL(x) ((x) & 0x0f)
+
+/* Read-only Version control register: Reset state: 0000 0000
+ * for first engineering samples
+ */
+#define AS_VERSION_CONTROL_REG 0x01
+#define AS_VERSION_CONTROL_RFU(x) (((x) >> 4))
+#define AS_VERSION_CONTROL_VERSION(x) ((x) & 0x0f)
+
+/* Read / Write (Indicator and timer register): Reset state: 0000 1111 */
+#define AS_INDICATOR_AND_TIMER_REG 0x02
+#define AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT 0
+#define AS_INDICATOR_AND_TIMER_VREF_SHIFT 4
+#define AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT 6
+
+/* Read / Write (Current set register): Reset state: 0110 1001 */
+#define AS_CURRENT_SET_REG 0x03
+#define AS_CURRENT_ASSIST_LIGHT_SHIFT 0
+#define AS_CURRENT_LED_DET_ON (1 << 3)
+#define AS_CURRENT_FLASH_CURRENT_SHIFT 4
+
+/* Read / Write (Control register): Reset state: 1011 0100 */
+#define AS_CONTROL_REG 0x04
+#define AS_CONTROL_MODE_SETTING_SHIFT 0
+#define AS_CONTROL_STROBE_ON (1 << 2)
+#define AS_CONTROL_OUT_ON (1 << 3)
+#define AS_CONTROL_EXT_TORCH_ON (1 << 4)
+#define AS_CONTROL_STROBE_TYPE_EDGE (0 << 5)
+#define AS_CONTROL_STROBE_TYPE_LEVEL (1 << 5)
+#define AS_CONTROL_COIL_PEAK_SHIFT 6
+
+/* Read only (D3 is read / write) (Fault and info): Reset state: 0000 x000 */
+#define AS_FAULT_INFO_REG 0x05
+#define AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT (1 << 1)
+#define AS_FAULT_INFO_INDICATOR_LED (1 << 2)
+#define AS_FAULT_INFO_LED_AMOUNT (1 << 3)
+#define AS_FAULT_INFO_TIMEOUT (1 << 4)
+#define AS_FAULT_INFO_OVER_TEMPERATURE (1 << 5)
+#define AS_FAULT_INFO_SHORT_CIRCUIT (1 << 6)
+#define AS_FAULT_INFO_OVER_VOLTAGE (1 << 7)
+
+/* Boost register */
+#define AS_BOOST_REG 0x0d
+#define AS_BOOST_CURRENT_DISABLE (0 << 0)
+#define AS_BOOST_CURRENT_ENABLE (1 << 0)
+
+/* Password register is used to unlock boost register writing */
+#define AS_PASSWORD_REG 0x0f
+#define AS_PASSWORD_UNLOCK_VALUE 0x55
+
+enum as_mode {
+ AS_MODE_EXT_TORCH = 0 << AS_CONTROL_MODE_SETTING_SHIFT,
+ AS_MODE_INDICATOR = 1 << AS_CONTROL_MODE_SETTING_SHIFT,
+ AS_MODE_ASSIST = 2 << AS_CONTROL_MODE_SETTING_SHIFT,
+ AS_MODE_FLASH = 3 << AS_CONTROL_MODE_SETTING_SHIFT,
+};
+
+/*
+ * struct as3645a
+ *
+ * @subdev: V4L2 subdev
+ * @pdata: Flash platform data
+ * @power_lock: Protects power_count
+ * @power_count: Power reference count
+ * @led_mode: V4L2 flash LED mode
+ * @timeout: Flash timeout in microseconds
+ * @flash_current: Flash current (0=200mA ... 15=500mA). Maximum
+ * values are 400mA for two LEDs and 500mA for one LED.
+ * @assist_current: Torch/Assist light current (0=20mA, 1=40mA ... 7=160mA)
+ * @indicator_current: Indicator LED current (0=0mA, 1=2.5mA ... 4=10mA)
+ * @strobe_source: Flash strobe source (software or external)
+ */
+struct as3645a {
+ struct v4l2_subdev subdev;
+ const struct as3645a_platform_data *pdata;
+
+ struct mutex power_lock;
+ int power_count;
+
+ /* Controls */
+ struct v4l2_ctrl_handler ctrls;
+
+ enum v4l2_flash_led_mode led_mode;
+ unsigned int timeout;
+ u8 flash_current;
+ u8 assist_current;
+ u8 indicator_current;
+ enum v4l2_flash_strobe_source strobe_source;
+};
+
+#define to_as3645a(sd) container_of(sd, struct as3645a, subdev)
+
+/* Return negative errno else zero on success */
+static int as3645a_write(struct as3645a *flash, u8 addr, u8 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+ int rval;
+
+ rval = i2c_smbus_write_byte_data(client, addr, val);
+
+ dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val,
+ rval < 0 ? "fail" : "ok");
+
+ return rval;
+}
+
+/* Return negative errno else a data byte received from the device. */
+static int as3645a_read(struct as3645a *flash, u8 addr)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+ int rval;
+
+ rval = i2c_smbus_read_byte_data(client, addr);
+
+ dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, rval,
+ rval < 0 ? "fail" : "ok");
+
+ return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * Hardware configuration and trigger
+ */
+
+/*
+ * as3645a_set_config - Set flash configuration registers
+ * @flash: The flash
+ *
+ * Configure the hardware with flash, assist and indicator currents, as well as
+ * flash timeout.
+ *
+ * Return 0 on success, or a negative error code if an I2C communication error
+ * occurred.
+ */
+static int as3645a_set_config(struct as3645a *flash)
+{
+ int ret;
+ u8 val;
+
+ val = (flash->flash_current << AS_CURRENT_FLASH_CURRENT_SHIFT)
+ | (flash->assist_current << AS_CURRENT_ASSIST_LIGHT_SHIFT)
+ | AS_CURRENT_LED_DET_ON;
+
+ ret = as3645a_write(flash, AS_CURRENT_SET_REG, val);
+ if (ret < 0)
+ return ret;
+
+ val = AS_TIMER_MS_TO_CODE(flash->timeout / 1000)
+ << AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT;
+
+ val |= (flash->pdata->vref << AS_INDICATOR_AND_TIMER_VREF_SHIFT)
+ | ((flash->indicator_current ? flash->indicator_current - 1 : 0)
+ << AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT);
+
+ return as3645a_write(flash, AS_INDICATOR_AND_TIMER_REG, val);
+}
+
+/*
+ * as3645a_set_control - Set flash control register
+ * @flash: The flash
+ * @mode: Desired output mode
+ * @on: Desired output state
+ *
+ * Configure the hardware with output mode and state.
+ *
+ * Return 0 on success, or a negative error code if an I2C communication error
+ * occurred.
+ */
+static int
+as3645a_set_control(struct as3645a *flash, enum as_mode mode, bool on)
+{
+ u8 reg;
+
+ /* Configure output parameters and operation mode. */
+ reg = (flash->pdata->peak << AS_CONTROL_COIL_PEAK_SHIFT)
+ | (on ? AS_CONTROL_OUT_ON : 0)
+ | mode;
+
+ if (flash->led_mode == V4L2_FLASH_LED_MODE_FLASH &&
+ flash->strobe_source == V4L2_FLASH_STROBE_SOURCE_EXTERNAL) {
+ reg |= AS_CONTROL_STROBE_TYPE_LEVEL
+ | AS_CONTROL_STROBE_ON;
+ }
+
+ return as3645a_write(flash, AS_CONTROL_REG, reg);
+}
+
+/*
+ * as3645a_set_output - Configure output and operation mode
+ * @flash: Flash controller
+ * @strobe: Strobe the flash (only valid in flash mode)
+ *
+ * Turn the LEDs output on/off and set the operation mode based on the current
+ * parameters.
+ *
+ * The AS3645A can't control the indicator LED independently of the flash/torch
+ * LED. If the flash controller is in V4L2_FLASH_LED_MODE_NONE mode, set the
+ * chip to indicator mode. Otherwise set it to assist light (torch) or flash
+ * mode.
+ *
+ * In indicator and assist modes, turn the output on/off based on the indicator
+ * and torch currents. In software strobe flash mode, turn the output on/off
+ * based on the strobe parameter.
+ */
+static int as3645a_set_output(struct as3645a *flash, bool strobe)
+{
+ enum as_mode mode;
+ bool on;
+
+ switch (flash->led_mode) {
+ case V4L2_FLASH_LED_MODE_NONE:
+ on = flash->indicator_current != 0;
+ mode = AS_MODE_INDICATOR;
+ break;
+ case V4L2_FLASH_LED_MODE_TORCH:
+ on = true;
+ mode = AS_MODE_ASSIST;
+ break;
+ case V4L2_FLASH_LED_MODE_FLASH:
+ on = strobe;
+ mode = AS_MODE_FLASH;
+ break;
+ default:
+ BUG();
+ }
+
+ /* Configure output parameters and operation mode. */
+ return as3645a_set_control(flash, mode, on);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static int as3645a_is_active(struct as3645a *flash)
+{
+ int ret;
+
+ ret = as3645a_read(flash, AS_CONTROL_REG);
+ return ret < 0 ? ret : !!(ret & AS_CONTROL_OUT_ON);
+}
+
+static int as3645a_read_fault(struct as3645a *flash)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+ int rval;
+
+ /* NOTE: reading register clear fault status */
+ rval = as3645a_read(flash, AS_FAULT_INFO_REG);
+ if (rval < 0)
+ return rval;
+
+ if (rval & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT)
+ dev_dbg(&client->dev, "Inductor Peak limit fault\n");
+
+ if (rval & AS_FAULT_INFO_INDICATOR_LED)
+ dev_dbg(&client->dev, "Indicator LED fault: "
+ "Short circuit or open loop\n");
+
+ dev_dbg(&client->dev, "%u connected LEDs\n",
+ rval & AS_FAULT_INFO_LED_AMOUNT ? 2 : 1);
+
+ if (rval & AS_FAULT_INFO_TIMEOUT)
+ dev_dbg(&client->dev, "Timeout fault\n");
+
+ if (rval & AS_FAULT_INFO_OVER_TEMPERATURE)
+ dev_dbg(&client->dev, "Over temperature fault\n");
+
+ if (rval & AS_FAULT_INFO_SHORT_CIRCUIT)
+ dev_dbg(&client->dev, "Short circuit fault\n");
+
+ if (rval & AS_FAULT_INFO_OVER_VOLTAGE)
+ dev_dbg(&client->dev, "Over voltage fault: "
+ "Indicates missing capacitor or open connection\n");
+
+ return rval;
+}
+
+static int as3645a_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct as3645a *flash =
+ container_of(ctrl->handler, struct as3645a, ctrls);
+ struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+ int value;
+
+ switch (ctrl->id) {
+ case V4L2_CID_FLASH_FAULT:
+ value = as3645a_read_fault(flash);
+ if (value < 0)
+ return value;
+
+ ctrl->cur.val = 0;
+ if (value & AS_FAULT_INFO_SHORT_CIRCUIT)
+ ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+ if (value & AS_FAULT_INFO_OVER_TEMPERATURE)
+ ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+ if (value & AS_FAULT_INFO_TIMEOUT)
+ ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
+ if (value & AS_FAULT_INFO_OVER_VOLTAGE)
+ ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
+ if (value & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT)
+ ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_CURRENT;
+ if (value & AS_FAULT_INFO_INDICATOR_LED)
+ ctrl->cur.val |= V4L2_FLASH_FAULT_INDICATOR;
+ break;
+
+ case V4L2_CID_FLASH_STROBE_STATUS:
+ if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
+ ctrl->cur.val = 0;
+ break;
+ }
+
+ value = as3645a_is_active(flash);
+ if (value < 0)
+ return value;
+
+ ctrl->cur.val = value;
+ break;
+ }
+
+ dev_dbg(&client->dev, "G_CTRL %08x:%d\n", ctrl->id, ctrl->cur.val);
+
+ return 0;
+}
+
+static int as3645a_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct as3645a *flash =
+ container_of(ctrl->handler, struct as3645a, ctrls);
+ struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+ int ret;
+
+ dev_dbg(&client->dev, "S_CTRL %08x:%d\n", ctrl->id, ctrl->val);
+
+ /* If a control that doesn't apply to the current mode is modified,
+ * we store the value and return immediately. The setting will be
+ * applied when the LED mode is changed. Otherwise we apply the setting
+ * immediately.
+ */
+
+ switch (ctrl->id) {
+ case V4L2_CID_FLASH_LED_MODE:
+ if (flash->indicator_current)
+ return -EBUSY;
+
+ ret = as3645a_set_config(flash);
+ if (ret < 0)
+ return ret;
+
+ flash->led_mode = ctrl->val;
+ return as3645a_set_output(flash, false);
+
+ case V4L2_CID_FLASH_STROBE_SOURCE:
+ flash->strobe_source = ctrl->val;
+
+ /* Applies to flash mode only. */
+ if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+ break;
+
+ return as3645a_set_output(flash, false);
+
+ case V4L2_CID_FLASH_STROBE:
+ if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+ return -EBUSY;
+
+ return as3645a_set_output(flash, true);
+
+ case V4L2_CID_FLASH_STROBE_STOP:
+ if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+ return -EBUSY;
+
+ return as3645a_set_output(flash, false);
+
+ case V4L2_CID_FLASH_TIMEOUT:
+ flash->timeout = ctrl->val;
+
+ /* Applies to flash mode only. */
+ if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+ break;
+
+ return as3645a_set_config(flash);
+
+ case V4L2_CID_FLASH_INTENSITY:
+ flash->flash_current = (ctrl->val - AS3645A_FLASH_INTENSITY_MIN)
+ / AS3645A_FLASH_INTENSITY_STEP;
+
+ /* Applies to flash mode only. */
+ if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+ break;
+
+ return as3645a_set_config(flash);
+
+ case V4L2_CID_FLASH_TORCH_INTENSITY:
+ flash->assist_current =
+ (ctrl->val - AS3645A_TORCH_INTENSITY_MIN)
+ / AS3645A_TORCH_INTENSITY_STEP;
+
+ /* Applies to torch mode only. */
+ if (flash->led_mode != V4L2_FLASH_LED_MODE_TORCH)
+ break;
+
+ return as3645a_set_config(flash);
+
+ case V4L2_CID_FLASH_INDICATOR_INTENSITY:
+ if (flash->led_mode != V4L2_FLASH_LED_MODE_NONE)
+ return -EBUSY;
+
+ flash->indicator_current =
+ (ctrl->val - AS3645A_INDICATOR_INTENSITY_MIN)
+ / AS3645A_INDICATOR_INTENSITY_STEP;
+
+ ret = as3645a_set_config(flash);
+ if (ret < 0)
+ return ret;
+
+ if ((ctrl->val == 0) == (ctrl->cur.val == 0))
+ break;
+
+ return as3645a_set_output(flash, false);
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops as3645a_ctrl_ops = {
+ .g_volatile_ctrl = as3645a_get_ctrl,
+ .s_ctrl = as3645a_set_ctrl,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+/* Put device into know state. */
+static int as3645a_setup(struct as3645a *flash)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+ int ret;
+
+ /* clear errors */
+ ret = as3645a_read(flash, AS_FAULT_INFO_REG);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&client->dev, "Fault info: %02x\n", ret);
+
+ ret = as3645a_set_config(flash);
+ if (ret < 0)
+ return ret;
+
+ ret = as3645a_set_output(flash, false);
+ if (ret < 0)
+ return ret;
+
+ /* read status */
+ ret = as3645a_read_fault(flash);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&client->dev, "AS_INDICATOR_AND_TIMER_REG: %02x\n",
+ as3645a_read(flash, AS_INDICATOR_AND_TIMER_REG));
+ dev_dbg(&client->dev, "AS_CURRENT_SET_REG: %02x\n",
+ as3645a_read(flash, AS_CURRENT_SET_REG));
+ dev_dbg(&client->dev, "AS_CONTROL_REG: %02x\n",
+ as3645a_read(flash, AS_CONTROL_REG));
+
+ return ret & ~AS_FAULT_INFO_LED_AMOUNT ? -EIO : 0;
+}
+
+static int __as3645a_set_power(struct as3645a *flash, int on)
+{
+ int ret;
+
+ if (!on)
+ as3645a_set_control(flash, AS_MODE_EXT_TORCH, false);
+
+ if (flash->pdata->set_power) {
+ ret = flash->pdata->set_power(&flash->subdev, on);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (!on)
+ return 0;
+
+ ret = as3645a_setup(flash);
+ if (ret < 0) {
+ if (flash->pdata->set_power)
+ flash->pdata->set_power(&flash->subdev, 0);
+ }
+
+ return ret;
+}
+
+static int as3645a_set_power(struct v4l2_subdev *sd, int on)
+{
+ struct as3645a *flash = to_as3645a(sd);
+ int ret = 0;
+
+ mutex_lock(&flash->power_lock);
+
+ if (flash->power_count == !on) {
+ ret = __as3645a_set_power(flash, !!on);
+ if (ret < 0)
+ goto done;
+ }
+
+ flash->power_count += on ? 1 : -1;
+ WARN_ON(flash->power_count < 0);
+
+done:
+ mutex_unlock(&flash->power_lock);
+ return ret;
+}
+
+static int as3645a_registered(struct v4l2_subdev *sd)
+{
+ struct as3645a *flash = to_as3645a(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int rval, man, model, rfu, version;
+ const char *vendor;
+
+ /* Power up the flash driver and read manufacturer ID, model ID, RFU
+ * and version.
+ */
+ rval = as3645a_set_power(&flash->subdev, 1);
+ if (rval < 0)
+ return rval;
+
+ rval = as3645a_read(flash, AS_DESIGN_INFO_REG);
+ if (rval < 0)
+ goto power_off;
+
+ man = AS_DESIGN_INFO_FACTORY(rval);
+ model = AS_DESIGN_INFO_MODEL(rval);
+
+ rval = as3645a_read(flash, AS_VERSION_CONTROL_REG);
+ if (rval < 0)
+ goto power_off;
+
+ rfu = AS_VERSION_CONTROL_RFU(rval);
+ version = AS_VERSION_CONTROL_VERSION(rval);
+
+ /* Verify the chip model and version. */
+ if (model != 0x01 || rfu != 0x00) {
+ dev_err(&client->dev, "AS3645A not detected "
+ "(model %d rfu %d)\n", model, rfu);
+ rval = -ENODEV;
+ goto power_off;
+ }
+
+ switch (man) {
+ case 1:
+ vendor = "AMS, Austria Micro Systems";
+ break;
+ case 2:
+ vendor = "ADI, Analog Devices Inc.";
+ break;
+ case 3:
+ vendor = "NSC, National Semiconductor";
+ break;
+ case 4:
+ vendor = "NXP";
+ break;
+ case 5:
+ vendor = "TI, Texas Instrument";
+ break;
+ default:
+ vendor = "Unknown";
+ }
+
+ dev_info(&client->dev, "Chip vendor: %s (%d) Version: %d\n", vendor,
+ man, version);
+
+ rval = as3645a_write(flash, AS_PASSWORD_REG, AS_PASSWORD_UNLOCK_VALUE);
+ if (rval < 0)
+ goto power_off;
+
+ rval = as3645a_write(flash, AS_BOOST_REG, AS_BOOST_CURRENT_DISABLE);
+ if (rval < 0)
+ goto power_off;
+
+ /* Setup default values. This makes sure that the chip is in a known
+ * state, in case the power rail can't be controlled.
+ */
+ rval = as3645a_setup(flash);
+
+power_off:
+ as3645a_set_power(&flash->subdev, 0);
+
+ return rval;
+}
+
+static int as3645a_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return as3645a_set_power(sd, 1);
+}
+
+static int as3645a_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return as3645a_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_core_ops as3645a_core_ops = {
+ .s_power = as3645a_set_power,
+};
+
+static const struct v4l2_subdev_ops as3645a_ops = {
+ .core = &as3645a_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops as3645a_internal_ops = {
+ .registered = as3645a_registered,
+ .open = as3645a_open,
+ .close = as3645a_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * I2C driver
+ */
+#ifdef CONFIG_PM
+
+static int as3645a_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct as3645a *flash = to_as3645a(subdev);
+ int rval;
+
+ if (flash->power_count == 0)
+ return 0;
+
+ rval = __as3645a_set_power(flash, 0);
+
+ dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok");
+
+ return rval;
+}
+
+static int as3645a_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct as3645a *flash = to_as3645a(subdev);
+ int rval;
+
+ if (flash->power_count == 0)
+ return 0;
+
+ rval = __as3645a_set_power(flash, 1);
+
+ dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok");
+
+ return rval;
+}
+
+#else
+
+#define as3645a_suspend NULL
+#define as3645a_resume NULL
+
+#endif /* CONFIG_PM */
+
+/*
+ * as3645a_init_controls - Create controls
+ * @flash: The flash
+ *
+ * The number of LEDs reported in platform data is used to compute default
+ * limits. Parameters passed through platform data can override those limits.
+ */
+static int as3645a_init_controls(struct as3645a *flash)
+{
+ const struct as3645a_platform_data *pdata = flash->pdata;
+ struct v4l2_ctrl *ctrl;
+ int maximum;
+
+ v4l2_ctrl_handler_init(&flash->ctrls, 10);
+
+ /* V4L2_CID_FLASH_LED_MODE */
+ v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops,
+ V4L2_CID_FLASH_LED_MODE, 2, ~7,
+ V4L2_FLASH_LED_MODE_NONE);
+
+ /* V4L2_CID_FLASH_STROBE_SOURCE */
+ v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops,
+ V4L2_CID_FLASH_STROBE_SOURCE,
+ pdata->ext_strobe ? 1 : 0,
+ pdata->ext_strobe ? ~3 : ~1,
+ V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
+
+ flash->strobe_source = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
+
+ /* V4L2_CID_FLASH_STROBE */
+ v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+ V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
+
+ /* V4L2_CID_FLASH_STROBE_STOP */
+ v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+ V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
+
+ /* V4L2_CID_FLASH_STROBE_STATUS */
+ ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+ V4L2_CID_FLASH_STROBE_STATUS, 0, 1, 1, 1);
+ if (ctrl != NULL)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+ /* V4L2_CID_FLASH_TIMEOUT */
+ maximum = pdata->timeout_max;
+
+ v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+ V4L2_CID_FLASH_TIMEOUT, AS3645A_FLASH_TIMEOUT_MIN,
+ maximum, AS3645A_FLASH_TIMEOUT_STEP, maximum);
+
+ flash->timeout = maximum;
+
+ /* V4L2_CID_FLASH_INTENSITY */
+ maximum = pdata->flash_max_current;
+
+ v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+ V4L2_CID_FLASH_INTENSITY, AS3645A_FLASH_INTENSITY_MIN,
+ maximum, AS3645A_FLASH_INTENSITY_STEP, maximum);
+
+ flash->flash_current = (maximum - AS3645A_FLASH_INTENSITY_MIN)
+ / AS3645A_FLASH_INTENSITY_STEP;
+
+ /* V4L2_CID_FLASH_TORCH_INTENSITY */
+ maximum = pdata->torch_max_current;
+
+ v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+ V4L2_CID_FLASH_TORCH_INTENSITY,
+ AS3645A_TORCH_INTENSITY_MIN, maximum,
+ AS3645A_TORCH_INTENSITY_STEP,
+ AS3645A_TORCH_INTENSITY_MIN);
+
+ flash->assist_current = 0;
+
+ /* V4L2_CID_FLASH_INDICATOR_INTENSITY */
+ v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+ V4L2_CID_FLASH_INDICATOR_INTENSITY,
+ AS3645A_INDICATOR_INTENSITY_MIN,
+ AS3645A_INDICATOR_INTENSITY_MAX,
+ AS3645A_INDICATOR_INTENSITY_STEP,
+ AS3645A_INDICATOR_INTENSITY_MIN);
+
+ flash->indicator_current = 0;
+
+ /* V4L2_CID_FLASH_FAULT */
+ ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+ V4L2_CID_FLASH_FAULT, 0,
+ V4L2_FLASH_FAULT_OVER_VOLTAGE |
+ V4L2_FLASH_FAULT_TIMEOUT |
+ V4L2_FLASH_FAULT_OVER_TEMPERATURE |
+ V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0);
+ if (ctrl != NULL)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+ flash->subdev.ctrl_handler = &flash->ctrls;
+
+ return flash->ctrls.error;
+}
+
+static int as3645a_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ struct as3645a *flash;
+ int ret;
+
+ if (client->dev.platform_data == NULL)
+ return -ENODEV;
+
+ flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+ if (flash == NULL)
+ return -ENOMEM;
+
+ flash->pdata = client->dev.platform_data;
+
+ v4l2_i2c_subdev_init(&flash->subdev, client, &as3645a_ops);
+ flash->subdev.internal_ops = &as3645a_internal_ops;
+ flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ ret = as3645a_init_controls(flash);
+ if (ret < 0)
+ goto done;
+
+ ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
+ if (ret < 0)
+ goto done;
+
+ flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+
+ mutex_init(&flash->power_lock);
+
+ flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
+
+done:
+ if (ret < 0) {
+ v4l2_ctrl_handler_free(&flash->ctrls);
+ kfree(flash);
+ }
+
+ return ret;
+}
+
+static int __exit as3645a_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct as3645a *flash = to_as3645a(subdev);
+
+ v4l2_device_unregister_subdev(subdev);
+ v4l2_ctrl_handler_free(&flash->ctrls);
+ media_entity_cleanup(&flash->subdev.entity);
+ mutex_destroy(&flash->power_lock);
+ kfree(flash);
+
+ return 0;
+}
+
+static const struct i2c_device_id as3645a_id_table[] = {
+ { AS3645A_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, as3645a_id_table);
+
+static const struct dev_pm_ops as3645a_pm_ops = {
+ .suspend = as3645a_suspend,
+ .resume = as3645a_resume,
+};
+
+static struct i2c_driver as3645a_i2c_driver = {
+ .driver = {
+ .name = AS3645A_NAME,
+ .pm = &as3645a_pm_ops,
+ },
+ .probe = as3645a_probe,
+ .remove = __exit_p(as3645a_remove),
+ .id_table = as3645a_id_table,
+};
+
+module_i2c_driver(as3645a_i2c_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
index 8c775c59e120..ec3f6a06f9c3 100644
--- a/drivers/media/video/atmel-isi.c
+++ b/drivers/media/video/atmel-isi.c
@@ -90,7 +90,10 @@ struct atmel_isi {
struct isi_dma_desc dma_desc[MAX_BUFFER_NUM];
struct completion complete;
+ /* ISI peripherial clock */
struct clk *pclk;
+ /* ISI_MCK, feed to camera sensor to generate pixel clock */
+ struct clk *mck;
unsigned int irq;
struct isi_platform_data *pdata;
@@ -766,6 +769,12 @@ static int isi_camera_add_device(struct soc_camera_device *icd)
if (ret)
return ret;
+ ret = clk_enable(isi->mck);
+ if (ret) {
+ clk_disable(isi->pclk);
+ return ret;
+ }
+
isi->icd = icd;
dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
icd->devnum);
@@ -779,6 +788,7 @@ static void isi_camera_remove_device(struct soc_camera_device *icd)
BUG_ON(icd != isi->icd);
+ clk_disable(isi->mck);
clk_disable(isi->pclk);
isi->icd = NULL;
@@ -803,7 +813,7 @@ static int isi_camera_querycap(struct soc_camera_host *ici,
return 0;
}
-static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt)
+static int isi_camera_set_bus_param(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -874,7 +884,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt)
if (isi->pdata->has_emb_sync)
cfg1 |= ISI_CFG1_EMB_SYNC;
- if (isi->pdata->isi_full_mode)
+ if (isi->pdata->full_mode)
cfg1 |= ISI_CFG1_FULL_MODE;
isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
@@ -912,6 +922,9 @@ static int __devexit atmel_isi_remove(struct platform_device *pdev)
isi->fb_descriptors_phys);
iounmap(isi->regs);
+ clk_unprepare(isi->mck);
+ clk_put(isi->mck);
+ clk_unprepare(isi->pclk);
clk_put(isi->pclk);
kfree(isi);
@@ -930,7 +943,7 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
struct isi_platform_data *pdata;
pdata = dev->platform_data;
- if (!pdata || !pdata->data_width_flags) {
+ if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) {
dev_err(&pdev->dev,
"No config available for Atmel ISI\n");
return -EINVAL;
@@ -944,6 +957,10 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
if (IS_ERR(pclk))
return PTR_ERR(pclk);
+ ret = clk_prepare(pclk);
+ if (ret)
+ goto err_clk_prepare_pclk;
+
isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL);
if (!isi) {
ret = -ENOMEM;
@@ -959,6 +976,23 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&isi->video_buffer_list);
INIT_LIST_HEAD(&isi->dma_desc_head);
+ /* Get ISI_MCK, provided by programmable clock or external clock */
+ isi->mck = clk_get(dev, "isi_mck");
+ if (IS_ERR(isi->mck)) {
+ dev_err(dev, "Failed to get isi_mck\n");
+ ret = PTR_ERR(isi->mck);
+ goto err_clk_get;
+ }
+
+ ret = clk_prepare(isi->mck);
+ if (ret)
+ goto err_clk_prepare_mck;
+
+ /* Set ISI_MCK's frequency, it should be faster than pixel clock */
+ ret = clk_set_rate(isi->mck, pdata->mck_hz);
+ if (ret < 0)
+ goto err_set_mck_rate;
+
isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev,
sizeof(struct fbd) * MAX_BUFFER_NUM,
&isi->fb_descriptors_phys,
@@ -1034,9 +1068,16 @@ err_alloc_ctx:
isi->p_fb_descriptors,
isi->fb_descriptors_phys);
err_alloc_descriptors:
+err_set_mck_rate:
+ clk_unprepare(isi->mck);
+err_clk_prepare_mck:
+ clk_put(isi->mck);
+err_clk_get:
kfree(isi);
err_alloc_isi:
- clk_put(isi->pclk);
+ clk_unprepare(pclk);
+err_clk_prepare_pclk:
+ clk_put(pclk);
return ret;
}
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index 0c3a5ba0e857..81ba9d9d1b52 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -2,6 +2,7 @@
config VIDEO_AU0828
tristate "Auvitek AU0828 support"
depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
+ depends on DVB_CAPTURE_DRIVERS
select I2C_ALGOBIT
select VIDEO_TVEEPROM
select VIDEOBUF_VMALLOC
diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
index cbdb65c34f21..05c299fa5d79 100644
--- a/drivers/media/video/au0828/au0828-i2c.c
+++ b/drivers/media/video/au0828/au0828-i2c.c
@@ -348,7 +348,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
}
}
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
int au0828_i2c_register(struct au0828_dev *dev)
{
dprintk(1, "%s()\n", __func__);
diff --git a/drivers/media/video/blackfin/Kconfig b/drivers/media/video/blackfin/Kconfig
new file mode 100644
index 000000000000..ecd5323768b7
--- /dev/null
+++ b/drivers/media/video/blackfin/Kconfig
@@ -0,0 +1,10 @@
+config VIDEO_BLACKFIN_CAPTURE
+ tristate "Blackfin Video Capture Driver"
+ depends on VIDEO_V4L2 && BLACKFIN && I2C
+ select VIDEOBUF2_DMA_CONTIG
+ help
+ V4L2 bridge driver for Blackfin video capture device.
+ Choose PPI or EPPI as its interface.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bfin_video_capture.
diff --git a/drivers/media/video/blackfin/Makefile b/drivers/media/video/blackfin/Makefile
new file mode 100644
index 000000000000..aa3a0a216387
--- /dev/null
+++ b/drivers/media/video/blackfin/Makefile
@@ -0,0 +1,2 @@
+bfin_video_capture-objs := bfin_capture.o ppi.o
+obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_video_capture.o
diff --git a/drivers/media/video/blackfin/bfin_capture.c b/drivers/media/video/blackfin/bfin_capture.c
new file mode 100644
index 000000000000..514fcf742f5a
--- /dev/null
+++ b/drivers/media/video/blackfin/bfin_capture.c
@@ -0,0 +1,1059 @@
+/*
+ * Analog Devices video capture driver
+ *
+ * Copyright (c) 2011 Analog Devices 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.
+ *
+ * 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/completion.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <asm/dma.h>
+
+#include <media/blackfin/bfin_capture.h>
+#include <media/blackfin/ppi.h>
+
+#define CAPTURE_DRV_NAME "bfin_capture"
+#define BCAP_MIN_NUM_BUF 2
+
+struct bcap_format {
+ char *desc;
+ u32 pixelformat;
+ enum v4l2_mbus_pixelcode mbus_code;
+ int bpp; /* bits per pixel */
+};
+
+struct bcap_buffer {
+ struct vb2_buffer vb;
+ struct list_head list;
+};
+
+struct bcap_device {
+ /* capture device instance */
+ struct v4l2_device v4l2_dev;
+ /* v4l2 control handler */
+ struct v4l2_ctrl_handler ctrl_handler;
+ /* device node data */
+ struct video_device *video_dev;
+ /* sub device instance */
+ struct v4l2_subdev *sd;
+ /* capture config */
+ struct bfin_capture_config *cfg;
+ /* ppi interface */
+ struct ppi_if *ppi;
+ /* current input */
+ unsigned int cur_input;
+ /* current selected standard */
+ v4l2_std_id std;
+ /* used to store pixel format */
+ struct v4l2_pix_format fmt;
+ /* bits per pixel*/
+ int bpp;
+ /* used to store sensor supported format */
+ struct bcap_format *sensor_formats;
+ /* number of sensor formats array */
+ int num_sensor_formats;
+ /* pointing to current video buffer */
+ struct bcap_buffer *cur_frm;
+ /* pointing to next video buffer */
+ struct bcap_buffer *next_frm;
+ /* buffer queue used in videobuf2 */
+ struct vb2_queue buffer_queue;
+ /* allocator-specific contexts for each plane */
+ struct vb2_alloc_ctx *alloc_ctx;
+ /* queue of filled frames */
+ struct list_head dma_queue;
+ /* used in videobuf2 callback */
+ spinlock_t lock;
+ /* used to access capture device */
+ struct mutex mutex;
+ /* used to wait ppi to complete one transfer */
+ struct completion comp;
+ /* prepare to stop */
+ bool stop;
+};
+
+struct bcap_fh {
+ struct v4l2_fh fh;
+ /* indicates whether this file handle is doing IO */
+ bool io_allowed;
+};
+
+static const struct bcap_format bcap_formats[] = {
+ {
+ .desc = "YCbCr 4:2:2 Interleaved UYVY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .bpp = 16,
+ },
+ {
+ .desc = "YCbCr 4:2:2 Interleaved YUYV",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .bpp = 16,
+ },
+ {
+ .desc = "RGB 565",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .bpp = 16,
+ },
+ {
+ .desc = "RGB 444",
+ .pixelformat = V4L2_PIX_FMT_RGB444,
+ .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+ .bpp = 16,
+ },
+
+};
+#define BCAP_MAX_FMTS ARRAY_SIZE(bcap_formats)
+
+static irqreturn_t bcap_isr(int irq, void *dev_id);
+
+static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb)
+{
+ return container_of(vb, struct bcap_buffer, vb);
+}
+
+static int bcap_init_sensor_formats(struct bcap_device *bcap_dev)
+{
+ enum v4l2_mbus_pixelcode code;
+ struct bcap_format *sf;
+ unsigned int num_formats = 0;
+ int i, j;
+
+ while (!v4l2_subdev_call(bcap_dev->sd, video,
+ enum_mbus_fmt, num_formats, &code))
+ num_formats++;
+ if (!num_formats)
+ return -ENXIO;
+
+ sf = kzalloc(num_formats * sizeof(*sf), GFP_KERNEL);
+ if (!sf)
+ return -ENOMEM;
+
+ for (i = 0; i < num_formats; i++) {
+ v4l2_subdev_call(bcap_dev->sd, video,
+ enum_mbus_fmt, i, &code);
+ for (j = 0; j < BCAP_MAX_FMTS; j++)
+ if (code == bcap_formats[j].mbus_code)
+ break;
+ if (j == BCAP_MAX_FMTS) {
+ /* we don't allow this sensor working with our bridge */
+ kfree(sf);
+ return -EINVAL;
+ }
+ sf[i] = bcap_formats[j];
+ }
+ bcap_dev->sensor_formats = sf;
+ bcap_dev->num_sensor_formats = num_formats;
+ return 0;
+}
+
+static void bcap_free_sensor_formats(struct bcap_device *bcap_dev)
+{
+ bcap_dev->num_sensor_formats = 0;
+ kfree(bcap_dev->sensor_formats);
+ bcap_dev->sensor_formats = NULL;
+}
+
+static int bcap_open(struct file *file)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct video_device *vfd = bcap_dev->video_dev;
+ struct bcap_fh *bcap_fh;
+
+ if (!bcap_dev->sd) {
+ v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n");
+ return -ENODEV;
+ }
+
+ bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL);
+ if (!bcap_fh) {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "unable to allocate memory for file handle object\n");
+ return -ENOMEM;
+ }
+
+ v4l2_fh_init(&bcap_fh->fh, vfd);
+
+ /* store pointer to v4l2_fh in private_data member of file */
+ file->private_data = &bcap_fh->fh;
+ v4l2_fh_add(&bcap_fh->fh);
+ bcap_fh->io_allowed = false;
+ return 0;
+}
+
+static int bcap_release(struct file *file)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_fh *fh = file->private_data;
+ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+ /* if this instance is doing IO */
+ if (bcap_fh->io_allowed)
+ vb2_queue_release(&bcap_dev->buffer_queue);
+
+ file->private_data = NULL;
+ v4l2_fh_del(&bcap_fh->fh);
+ v4l2_fh_exit(&bcap_fh->fh);
+ kfree(bcap_fh);
+ return 0;
+}
+
+static int bcap_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ return vb2_mmap(&bcap_dev->buffer_queue, vma);
+}
+
+#ifndef CONFIG_MMU
+static unsigned long bcap_get_unmapped_area(struct file *file,
+ unsigned long addr,
+ unsigned long len,
+ unsigned long pgoff,
+ unsigned long flags)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ return vb2_get_unmapped_area(&bcap_dev->buffer_queue,
+ addr,
+ len,
+ pgoff,
+ flags);
+}
+#endif
+
+static unsigned int bcap_poll(struct file *file, poll_table *wait)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ return vb2_poll(&bcap_dev->buffer_queue, file, wait);
+}
+
+static int bcap_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+
+ if (*nbuffers < BCAP_MIN_NUM_BUF)
+ *nbuffers = BCAP_MIN_NUM_BUF;
+
+ *nplanes = 1;
+ sizes[0] = bcap_dev->fmt.sizeimage;
+ alloc_ctxs[0] = bcap_dev->alloc_ctx;
+
+ return 0;
+}
+
+static int bcap_buffer_init(struct vb2_buffer *vb)
+{
+ struct bcap_buffer *buf = to_bcap_vb(vb);
+
+ INIT_LIST_HEAD(&buf->list);
+ return 0;
+}
+
+static int bcap_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct bcap_buffer *buf = to_bcap_vb(vb);
+ unsigned long size;
+
+ size = bcap_dev->fmt.sizeimage;
+ if (vb2_plane_size(vb, 0) < size) {
+ v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(&buf->vb, 0, size);
+
+ return 0;
+}
+
+static void bcap_buffer_queue(struct vb2_buffer *vb)
+{
+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct bcap_buffer *buf = to_bcap_vb(vb);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bcap_dev->lock, flags);
+ list_add_tail(&buf->list, &bcap_dev->dma_queue);
+ spin_unlock_irqrestore(&bcap_dev->lock, flags);
+}
+
+static void bcap_buffer_cleanup(struct vb2_buffer *vb)
+{
+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct bcap_buffer *buf = to_bcap_vb(vb);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bcap_dev->lock, flags);
+ list_del_init(&buf->list);
+ spin_unlock_irqrestore(&bcap_dev->lock, flags);
+}
+
+static void bcap_lock(struct vb2_queue *vq)
+{
+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+ mutex_lock(&bcap_dev->mutex);
+}
+
+static void bcap_unlock(struct vb2_queue *vq)
+{
+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+ mutex_unlock(&bcap_dev->mutex);
+}
+
+static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+ struct ppi_if *ppi = bcap_dev->ppi;
+ struct ppi_params params;
+ int ret;
+
+ /* enable streamon on the sub device */
+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1);
+ if (ret && (ret != -ENOIOCTLCMD)) {
+ v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n");
+ return ret;
+ }
+
+ /* set ppi params */
+ params.width = bcap_dev->fmt.width;
+ params.height = bcap_dev->fmt.height;
+ params.bpp = bcap_dev->bpp;
+ params.ppi_control = bcap_dev->cfg->ppi_control;
+ params.int_mask = bcap_dev->cfg->int_mask;
+ params.blank_clocks = bcap_dev->cfg->blank_clocks;
+ ret = ppi->ops->set_params(ppi, &params);
+ if (ret < 0) {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "Error in setting ppi params\n");
+ return ret;
+ }
+
+ /* attach ppi DMA irq handler */
+ ret = ppi->ops->attach_irq(ppi, bcap_isr);
+ if (ret < 0) {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "Error in attaching interrupt handler\n");
+ return ret;
+ }
+
+ INIT_COMPLETION(bcap_dev->comp);
+ bcap_dev->stop = false;
+ return 0;
+}
+
+static int bcap_stop_streaming(struct vb2_queue *vq)
+{
+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+ struct ppi_if *ppi = bcap_dev->ppi;
+ int ret;
+
+ if (!vb2_is_streaming(vq))
+ return 0;
+
+ bcap_dev->stop = true;
+ wait_for_completion(&bcap_dev->comp);
+ ppi->ops->stop(ppi);
+ ppi->ops->detach_irq(ppi);
+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 0);
+ if (ret && (ret != -ENOIOCTLCMD))
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "stream off failed in subdev\n");
+
+ /* release all active buffers */
+ while (!list_empty(&bcap_dev->dma_queue)) {
+ bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+ struct bcap_buffer, list);
+ list_del(&bcap_dev->next_frm->list);
+ vb2_buffer_done(&bcap_dev->next_frm->vb, VB2_BUF_STATE_ERROR);
+ }
+ return 0;
+}
+
+static struct vb2_ops bcap_video_qops = {
+ .queue_setup = bcap_queue_setup,
+ .buf_init = bcap_buffer_init,
+ .buf_prepare = bcap_buffer_prepare,
+ .buf_cleanup = bcap_buffer_cleanup,
+ .buf_queue = bcap_buffer_queue,
+ .wait_prepare = bcap_unlock,
+ .wait_finish = bcap_lock,
+ .start_streaming = bcap_start_streaming,
+ .stop_streaming = bcap_stop_streaming,
+};
+
+static int bcap_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *req_buf)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct vb2_queue *vq = &bcap_dev->buffer_queue;
+ struct v4l2_fh *fh = file->private_data;
+ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+ if (vb2_is_busy(vq))
+ return -EBUSY;
+
+ bcap_fh->io_allowed = true;
+
+ return vb2_reqbufs(vq, req_buf);
+}
+
+static int bcap_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ return vb2_querybuf(&bcap_dev->buffer_queue, buf);
+}
+
+static int bcap_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_fh *fh = file->private_data;
+ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+ if (!bcap_fh->io_allowed)
+ return -EBUSY;
+
+ return vb2_qbuf(&bcap_dev->buffer_queue, buf);
+}
+
+static int bcap_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_fh *fh = file->private_data;
+ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+ if (!bcap_fh->io_allowed)
+ return -EBUSY;
+
+ return vb2_dqbuf(&bcap_dev->buffer_queue,
+ buf, file->f_flags & O_NONBLOCK);
+}
+
+static irqreturn_t bcap_isr(int irq, void *dev_id)
+{
+ struct ppi_if *ppi = dev_id;
+ struct bcap_device *bcap_dev = ppi->priv;
+ struct timeval timevalue;
+ struct vb2_buffer *vb = &bcap_dev->cur_frm->vb;
+ dma_addr_t addr;
+
+ spin_lock(&bcap_dev->lock);
+
+ if (bcap_dev->cur_frm != bcap_dev->next_frm) {
+ do_gettimeofday(&timevalue);
+ vb->v4l2_buf.timestamp = timevalue;
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ bcap_dev->cur_frm = bcap_dev->next_frm;
+ }
+
+ ppi->ops->stop(ppi);
+
+ if (bcap_dev->stop) {
+ complete(&bcap_dev->comp);
+ } else {
+ if (!list_empty(&bcap_dev->dma_queue)) {
+ bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+ struct bcap_buffer, list);
+ list_del(&bcap_dev->next_frm->list);
+ addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->next_frm->vb, 0);
+ ppi->ops->update_addr(ppi, (unsigned long)addr);
+ }
+ ppi->ops->start(ppi);
+ }
+
+ spin_unlock(&bcap_dev->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int bcap_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct bcap_fh *fh = file->private_data;
+ struct ppi_if *ppi = bcap_dev->ppi;
+ dma_addr_t addr;
+ int ret;
+
+ if (!fh->io_allowed)
+ return -EBUSY;
+
+ /* call streamon to start streaming in videobuf */
+ ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type);
+ if (ret)
+ return ret;
+
+ /* if dma queue is empty, return error */
+ if (list_empty(&bcap_dev->dma_queue)) {
+ v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* get the next frame from the dma queue */
+ bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+ struct bcap_buffer, list);
+ bcap_dev->cur_frm = bcap_dev->next_frm;
+ /* remove buffer from the dma queue */
+ list_del(&bcap_dev->cur_frm->list);
+ addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0);
+ /* update DMA address */
+ ppi->ops->update_addr(ppi, (unsigned long)addr);
+ /* enable ppi */
+ ppi->ops->start(ppi);
+
+ return 0;
+err:
+ vb2_streamoff(&bcap_dev->buffer_queue, buf_type);
+ return ret;
+}
+
+static int bcap_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct bcap_fh *fh = file->private_data;
+
+ if (!fh->io_allowed)
+ return -EBUSY;
+
+ return vb2_streamoff(&bcap_dev->buffer_queue, buf_type);
+}
+
+static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ return v4l2_subdev_call(bcap_dev->sd, video, querystd, std);
+}
+
+static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ *std = bcap_dev->std;
+ return 0;
+}
+
+static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ int ret;
+
+ if (vb2_is_busy(&bcap_dev->buffer_queue))
+ return -EBUSY;
+
+ ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std);
+ if (ret < 0)
+ return ret;
+
+ bcap_dev->std = *std;
+ return 0;
+}
+
+static int bcap_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct bfin_capture_config *config = bcap_dev->cfg;
+ int ret;
+ u32 status;
+
+ if (input->index >= config->num_inputs)
+ return -EINVAL;
+
+ *input = config->inputs[input->index];
+ /* get input status */
+ ret = v4l2_subdev_call(bcap_dev->sd, video, g_input_status, &status);
+ if (!ret)
+ input->status = status;
+ return 0;
+}
+
+static int bcap_g_input(struct file *file, void *priv, unsigned int *index)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ *index = bcap_dev->cur_input;
+ return 0;
+}
+
+static int bcap_s_input(struct file *file, void *priv, unsigned int index)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct bfin_capture_config *config = bcap_dev->cfg;
+ struct bcap_route *route;
+ int ret;
+
+ if (vb2_is_busy(&bcap_dev->buffer_queue))
+ return -EBUSY;
+
+ if (index >= config->num_inputs)
+ return -EINVAL;
+
+ route = &config->routes[index];
+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing,
+ route->input, route->output, 0);
+ if ((ret < 0) && (ret != -ENOIOCTLCMD)) {
+ v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n");
+ return ret;
+ }
+ bcap_dev->cur_input = index;
+ return 0;
+}
+
+static int bcap_try_format(struct bcap_device *bcap,
+ struct v4l2_pix_format *pixfmt,
+ enum v4l2_mbus_pixelcode *mbus_code,
+ int *bpp)
+{
+ struct bcap_format *sf = bcap->sensor_formats;
+ struct bcap_format *fmt = NULL;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ int ret, i;
+
+ for (i = 0; i < bcap->num_sensor_formats; i++) {
+ fmt = &sf[i];
+ if (pixfmt->pixelformat == fmt->pixelformat)
+ break;
+ }
+ if (i == bcap->num_sensor_formats)
+ fmt = &sf[0];
+
+ if (mbus_code)
+ *mbus_code = fmt->mbus_code;
+ if (bpp)
+ *bpp = fmt->bpp;
+ v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code);
+ ret = v4l2_subdev_call(bcap->sd, video,
+ try_mbus_fmt, &mbus_fmt);
+ if (ret < 0)
+ return ret;
+ v4l2_fill_pix_format(pixfmt, &mbus_fmt);
+ pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8;
+ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+ return 0;
+}
+
+static int bcap_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct bcap_format *sf = bcap_dev->sensor_formats;
+
+ if (fmt->index >= bcap_dev->num_sensor_formats)
+ return -EINVAL;
+
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strlcpy(fmt->description,
+ sf[fmt->index].desc,
+ sizeof(fmt->description));
+ fmt->pixelformat = sf[fmt->index].pixelformat;
+ return 0;
+}
+
+static int bcap_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+ return bcap_try_format(bcap_dev, pixfmt, NULL, NULL);
+}
+
+static int bcap_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ fmt->fmt.pix = bcap_dev->fmt;
+ return 0;
+}
+
+static int bcap_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ struct v4l2_mbus_framefmt mbus_fmt;
+ enum v4l2_mbus_pixelcode mbus_code;
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+ int ret, bpp;
+
+ if (vb2_is_busy(&bcap_dev->buffer_queue))
+ return -EBUSY;
+
+ /* see if format works */
+ ret = bcap_try_format(bcap_dev, pixfmt, &mbus_code, &bpp);
+ if (ret < 0)
+ return ret;
+
+ v4l2_fill_mbus_format(&mbus_fmt, pixfmt, mbus_code);
+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt);
+ if (ret < 0)
+ return ret;
+ bcap_dev->fmt = *pixfmt;
+ bcap_dev->bpp = bpp;
+ return 0;
+}
+
+static int bcap_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info));
+ strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card));
+ return 0;
+}
+
+static int bcap_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a);
+}
+
+static int bcap_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a);
+}
+
+static int bcap_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ return v4l2_subdev_call(bcap_dev->sd, core,
+ g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int bcap_dbg_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ return v4l2_subdev_call(bcap_dev->sd, core,
+ g_register, reg);
+}
+
+static int bcap_dbg_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+
+ return v4l2_subdev_call(bcap_dev->sd, core,
+ s_register, reg);
+}
+#endif
+
+static int bcap_log_status(struct file *file, void *priv)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ /* status for sub devices */
+ v4l2_device_call_all(&bcap_dev->v4l2_dev, 0, core, log_status);
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
+ .vidioc_querycap = bcap_querycap,
+ .vidioc_g_fmt_vid_cap = bcap_g_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = bcap_enum_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = bcap_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = bcap_try_fmt_vid_cap,
+ .vidioc_enum_input = bcap_enum_input,
+ .vidioc_g_input = bcap_g_input,
+ .vidioc_s_input = bcap_s_input,
+ .vidioc_querystd = bcap_querystd,
+ .vidioc_s_std = bcap_s_std,
+ .vidioc_g_std = bcap_g_std,
+ .vidioc_reqbufs = bcap_reqbufs,
+ .vidioc_querybuf = bcap_querybuf,
+ .vidioc_qbuf = bcap_qbuf,
+ .vidioc_dqbuf = bcap_dqbuf,
+ .vidioc_streamon = bcap_streamon,
+ .vidioc_streamoff = bcap_streamoff,
+ .vidioc_g_parm = bcap_g_parm,
+ .vidioc_s_parm = bcap_s_parm,
+ .vidioc_g_chip_ident = bcap_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = bcap_dbg_g_register,
+ .vidioc_s_register = bcap_dbg_s_register,
+#endif
+ .vidioc_log_status = bcap_log_status,
+};
+
+static struct v4l2_file_operations bcap_fops = {
+ .owner = THIS_MODULE,
+ .open = bcap_open,
+ .release = bcap_release,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = bcap_mmap,
+#ifndef CONFIG_MMU
+ .get_unmapped_area = bcap_get_unmapped_area,
+#endif
+ .poll = bcap_poll
+};
+
+static int __devinit bcap_probe(struct platform_device *pdev)
+{
+ struct bcap_device *bcap_dev;
+ struct video_device *vfd;
+ struct i2c_adapter *i2c_adap;
+ struct bfin_capture_config *config;
+ struct vb2_queue *q;
+ int ret;
+
+ config = pdev->dev.platform_data;
+ if (!config) {
+ v4l2_err(pdev->dev.driver, "Unable to get board config\n");
+ return -ENODEV;
+ }
+
+ bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL);
+ if (!bcap_dev) {
+ v4l2_err(pdev->dev.driver, "Unable to alloc bcap_dev\n");
+ return -ENOMEM;
+ }
+
+ bcap_dev->cfg = config;
+
+ bcap_dev->ppi = ppi_create_instance(config->ppi_info);
+ if (!bcap_dev->ppi) {
+ v4l2_err(pdev->dev.driver, "Unable to create ppi\n");
+ ret = -ENODEV;
+ goto err_free_dev;
+ }
+ bcap_dev->ppi->priv = bcap_dev;
+
+ bcap_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(bcap_dev->alloc_ctx)) {
+ ret = PTR_ERR(bcap_dev->alloc_ctx);
+ goto err_free_ppi;
+ }
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ ret = -ENOMEM;
+ v4l2_err(pdev->dev.driver, "Unable to alloc video device\n");
+ goto err_cleanup_ctx;
+ }
+
+ /* initialize field of video device */
+ vfd->release = video_device_release;
+ vfd->fops = &bcap_fops;
+ vfd->ioctl_ops = &bcap_ioctl_ops;
+ vfd->tvnorms = 0;
+ vfd->v4l2_dev = &bcap_dev->v4l2_dev;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+ strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name));
+ bcap_dev->video_dev = vfd;
+
+ ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev);
+ if (ret) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to register v4l2 device\n");
+ goto err_release_vdev;
+ }
+ v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n");
+
+ bcap_dev->v4l2_dev.ctrl_handler = &bcap_dev->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(&bcap_dev->ctrl_handler, 0);
+ if (ret) {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "Unable to init control handler\n");
+ goto err_unreg_v4l2;
+ }
+
+ spin_lock_init(&bcap_dev->lock);
+ /* initialize queue */
+ q = &bcap_dev->buffer_queue;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP;
+ q->drv_priv = bcap_dev;
+ q->buf_struct_size = sizeof(struct bcap_buffer);
+ q->ops = &bcap_video_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+
+ vb2_queue_init(q);
+
+ mutex_init(&bcap_dev->mutex);
+ init_completion(&bcap_dev->comp);
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&bcap_dev->dma_queue);
+
+ vfd->lock = &bcap_dev->mutex;
+
+ /* register video device */
+ ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "Unable to register video device\n");
+ goto err_free_handler;
+ }
+ video_set_drvdata(bcap_dev->video_dev, bcap_dev);
+ v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n",
+ video_device_node_name(vfd));
+
+ /* load up the subdevice */
+ i2c_adap = i2c_get_adapter(config->i2c_adapter_id);
+ if (!i2c_adap) {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "Unable to find i2c adapter\n");
+ goto err_unreg_vdev;
+
+ }
+ bcap_dev->sd = v4l2_i2c_new_subdev_board(&bcap_dev->v4l2_dev,
+ i2c_adap,
+ &config->board_info,
+ NULL);
+ if (bcap_dev->sd) {
+ int i;
+ /* update tvnorms from the sub devices */
+ for (i = 0; i < config->num_inputs; i++)
+ vfd->tvnorms |= config->inputs[i].std;
+ } else {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "Unable to register sub device\n");
+ goto err_unreg_vdev;
+ }
+
+ v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n");
+
+ /* now we can probe the default state */
+ if (vfd->tvnorms) {
+ v4l2_std_id std;
+ ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std);
+ if (ret) {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "Unable to get std\n");
+ goto err_unreg_vdev;
+ }
+ bcap_dev->std = std;
+ }
+ ret = bcap_init_sensor_formats(bcap_dev);
+ if (ret) {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "Unable to create sensor formats table\n");
+ goto err_unreg_vdev;
+ }
+ return 0;
+err_unreg_vdev:
+ video_unregister_device(bcap_dev->video_dev);
+ bcap_dev->video_dev = NULL;
+err_free_handler:
+ v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler);
+err_unreg_v4l2:
+ v4l2_device_unregister(&bcap_dev->v4l2_dev);
+err_release_vdev:
+ if (bcap_dev->video_dev)
+ video_device_release(bcap_dev->video_dev);
+err_cleanup_ctx:
+ vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx);
+err_free_ppi:
+ ppi_delete_instance(bcap_dev->ppi);
+err_free_dev:
+ kfree(bcap_dev);
+ return ret;
+}
+
+static int __devexit bcap_remove(struct platform_device *pdev)
+{
+ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+ struct bcap_device *bcap_dev = container_of(v4l2_dev,
+ struct bcap_device, v4l2_dev);
+
+ bcap_free_sensor_formats(bcap_dev);
+ video_unregister_device(bcap_dev->video_dev);
+ v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler);
+ v4l2_device_unregister(v4l2_dev);
+ vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx);
+ ppi_delete_instance(bcap_dev->ppi);
+ kfree(bcap_dev);
+ return 0;
+}
+
+static struct platform_driver bcap_driver = {
+ .driver = {
+ .name = CAPTURE_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = bcap_probe,
+ .remove = __devexit_p(bcap_remove),
+};
+
+static __init int bcap_init(void)
+{
+ return platform_driver_register(&bcap_driver);
+}
+
+static __exit void bcap_exit(void)
+{
+ platform_driver_unregister(&bcap_driver);
+}
+
+module_init(bcap_init);
+module_exit(bcap_exit);
+
+MODULE_DESCRIPTION("Analog Devices blackfin video capture driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/blackfin/ppi.c b/drivers/media/video/blackfin/ppi.c
new file mode 100644
index 000000000000..d29592186b02
--- /dev/null
+++ b/drivers/media/video/blackfin/ppi.c
@@ -0,0 +1,271 @@
+/*
+ * ppi.c Analog Devices Parallel Peripheral Interface driver
+ *
+ * Copyright (c) 2011 Analog Devices 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.
+ *
+ * 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/slab.h>
+
+#include <asm/bfin_ppi.h>
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include <media/blackfin/ppi.h>
+
+static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler);
+static void ppi_detach_irq(struct ppi_if *ppi);
+static int ppi_start(struct ppi_if *ppi);
+static int ppi_stop(struct ppi_if *ppi);
+static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params);
+static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr);
+
+static const struct ppi_ops ppi_ops = {
+ .attach_irq = ppi_attach_irq,
+ .detach_irq = ppi_detach_irq,
+ .start = ppi_start,
+ .stop = ppi_stop,
+ .set_params = ppi_set_params,
+ .update_addr = ppi_update_addr,
+};
+
+static irqreturn_t ppi_irq_err(int irq, void *dev_id)
+{
+ struct ppi_if *ppi = dev_id;
+ const struct ppi_info *info = ppi->info;
+
+ switch (info->type) {
+ case PPI_TYPE_PPI:
+ {
+ struct bfin_ppi_regs *reg = info->base;
+ unsigned short status;
+
+ /* register on bf561 is cleared when read
+ * others are W1C
+ */
+ status = bfin_read16(&reg->status);
+ bfin_write16(&reg->status, 0xff00);
+ break;
+ }
+ case PPI_TYPE_EPPI:
+ {
+ struct bfin_eppi_regs *reg = info->base;
+ bfin_write16(&reg->status, 0xffff);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler)
+{
+ const struct ppi_info *info = ppi->info;
+ int ret;
+
+ ret = request_dma(info->dma_ch, "PPI_DMA");
+
+ if (ret) {
+ pr_err("Unable to allocate DMA channel for PPI\n");
+ return ret;
+ }
+ set_dma_callback(info->dma_ch, handler, ppi);
+
+ if (ppi->err_int) {
+ ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi);
+ if (ret) {
+ pr_err("Unable to allocate IRQ for PPI\n");
+ free_dma(info->dma_ch);
+ }
+ }
+ return ret;
+}
+
+static void ppi_detach_irq(struct ppi_if *ppi)
+{
+ const struct ppi_info *info = ppi->info;
+
+ if (ppi->err_int)
+ free_irq(info->irq_err, ppi);
+ free_dma(info->dma_ch);
+}
+
+static int ppi_start(struct ppi_if *ppi)
+{
+ const struct ppi_info *info = ppi->info;
+
+ /* enable DMA */
+ enable_dma(info->dma_ch);
+
+ /* enable PPI */
+ ppi->ppi_control |= PORT_EN;
+ switch (info->type) {
+ case PPI_TYPE_PPI:
+ {
+ struct bfin_ppi_regs *reg = info->base;
+ bfin_write16(&reg->control, ppi->ppi_control);
+ break;
+ }
+ case PPI_TYPE_EPPI:
+ {
+ struct bfin_eppi_regs *reg = info->base;
+ bfin_write32(&reg->control, ppi->ppi_control);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ SSYNC();
+ return 0;
+}
+
+static int ppi_stop(struct ppi_if *ppi)
+{
+ const struct ppi_info *info = ppi->info;
+
+ /* disable PPI */
+ ppi->ppi_control &= ~PORT_EN;
+ switch (info->type) {
+ case PPI_TYPE_PPI:
+ {
+ struct bfin_ppi_regs *reg = info->base;
+ bfin_write16(&reg->control, ppi->ppi_control);
+ break;
+ }
+ case PPI_TYPE_EPPI:
+ {
+ struct bfin_eppi_regs *reg = info->base;
+ bfin_write32(&reg->control, ppi->ppi_control);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ /* disable DMA */
+ clear_dma_irqstat(info->dma_ch);
+ disable_dma(info->dma_ch);
+
+ SSYNC();
+ return 0;
+}
+
+static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
+{
+ const struct ppi_info *info = ppi->info;
+ int dma32 = 0;
+ int dma_config, bytes_per_line, lines_per_frame;
+
+ bytes_per_line = params->width * params->bpp / 8;
+ lines_per_frame = params->height;
+ if (params->int_mask == 0xFFFFFFFF)
+ ppi->err_int = false;
+ else
+ ppi->err_int = true;
+
+ dma_config = (DMA_FLOW_STOP | WNR | RESTART | DMA2D | DI_EN);
+ ppi->ppi_control = params->ppi_control & ~PORT_EN;
+ switch (info->type) {
+ case PPI_TYPE_PPI:
+ {
+ struct bfin_ppi_regs *reg = info->base;
+
+ if (params->ppi_control & DMA32)
+ dma32 = 1;
+
+ bfin_write16(&reg->control, ppi->ppi_control);
+ bfin_write16(&reg->count, bytes_per_line - 1);
+ bfin_write16(&reg->frame, lines_per_frame);
+ break;
+ }
+ case PPI_TYPE_EPPI:
+ {
+ struct bfin_eppi_regs *reg = info->base;
+
+ if ((params->ppi_control & PACK_EN)
+ || (params->ppi_control & 0x38000) > DLEN_16)
+ dma32 = 1;
+
+ bfin_write32(&reg->control, ppi->ppi_control);
+ bfin_write16(&reg->line, bytes_per_line + params->blank_clocks);
+ bfin_write16(&reg->frame, lines_per_frame);
+ bfin_write16(&reg->hdelay, 0);
+ bfin_write16(&reg->vdelay, 0);
+ bfin_write16(&reg->hcount, bytes_per_line);
+ bfin_write16(&reg->vcount, lines_per_frame);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ if (dma32) {
+ dma_config |= WDSIZE_32;
+ set_dma_x_count(info->dma_ch, bytes_per_line >> 2);
+ set_dma_x_modify(info->dma_ch, 4);
+ set_dma_y_modify(info->dma_ch, 4);
+ } else {
+ dma_config |= WDSIZE_16;
+ set_dma_x_count(info->dma_ch, bytes_per_line >> 1);
+ set_dma_x_modify(info->dma_ch, 2);
+ set_dma_y_modify(info->dma_ch, 2);
+ }
+ set_dma_y_count(info->dma_ch, lines_per_frame);
+ set_dma_config(info->dma_ch, dma_config);
+
+ SSYNC();
+ return 0;
+}
+
+static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr)
+{
+ set_dma_start_addr(ppi->info->dma_ch, addr);
+}
+
+struct ppi_if *ppi_create_instance(const struct ppi_info *info)
+{
+ struct ppi_if *ppi;
+
+ if (!info || !info->pin_req)
+ return NULL;
+
+ if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) {
+ pr_err("request peripheral failed\n");
+ return NULL;
+ }
+
+ ppi = kzalloc(sizeof(*ppi), GFP_KERNEL);
+ if (!ppi) {
+ peripheral_free_list(info->pin_req);
+ pr_err("unable to allocate memory for ppi handle\n");
+ return NULL;
+ }
+ ppi->ops = &ppi_ops;
+ ppi->info = info;
+
+ pr_info("ppi probe success\n");
+ return ppi;
+}
+
+void ppi_delete_instance(struct ppi_if *ppi)
+{
+ peripheral_free_list(ppi->info->pin_req);
+ kfree(ppi);
+}
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 859eabf57978..377bf05b1efd 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -514,15 +514,4 @@ static struct i2c_driver bt819_driver = {
.id_table = bt819_id,
};
-static __init int init_bt819(void)
-{
- return i2c_add_driver(&bt819_driver);
-}
-
-static __exit void exit_bt819(void)
-{
- i2c_del_driver(&bt819_driver);
-}
-
-module_init(init_bt819);
-module_exit(exit_bt819);
+module_i2c_driver(bt819_driver);
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index a43059d4c799..7e5bd365c239 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -270,15 +270,4 @@ static struct i2c_driver bt856_driver = {
.id_table = bt856_id,
};
-static __init int init_bt856(void)
-{
- return i2c_add_driver(&bt856_driver);
-}
-
-static __exit void exit_bt856(void)
-{
- i2c_del_driver(&bt856_driver);
-}
-
-module_init(init_bt856);
-module_exit(exit_bt856);
+module_i2c_driver(bt856_driver);
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 4e5dcea0501d..905320b67a1c 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -240,15 +240,4 @@ static struct i2c_driver bt866_driver = {
.id_table = bt866_id,
};
-static __init int init_bt866(void)
-{
- return i2c_add_driver(&bt866_driver);
-}
-
-static __exit void exit_bt866(void)
-{
- i2c_del_driver(&bt866_driver);
-}
-
-module_init(init_bt866);
-module_exit(exit_bt866);
+module_i2c_driver(bt866_driver);
diff --git a/drivers/media/video/bt8xx/bt848.h b/drivers/media/video/bt8xx/bt848.h
index 0bcd95303bb0..c37e6acffded 100644
--- a/drivers/media/video/bt8xx/bt848.h
+++ b/drivers/media/video/bt8xx/bt848.h
@@ -30,6 +30,10 @@
#ifndef PCI_DEVICE_ID_BT849
#define PCI_DEVICE_ID_BT849 0x351
#endif
+#ifndef PCI_DEVICE_ID_FUSION879
+#define PCI_DEVICE_ID_FUSION879 0x36c
+#endif
+
#ifndef PCI_DEVICE_ID_BT878
#define PCI_DEVICE_ID_BT878 0x36e
#endif
@@ -37,7 +41,6 @@
#define PCI_DEVICE_ID_BT879 0x36f
#endif
-
/* Brooktree 848 registers */
#define BT848_DSTATUS 0x000
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 5939021d8eba..ff2933ab705f 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -80,6 +80,8 @@ static void phytec_muxsel(struct bttv *btv, unsigned int input);
static void gv800s_muxsel(struct bttv *btv, unsigned int input);
static void gv800s_init(struct bttv *btv);
+static void td3116_muxsel(struct bttv *btv, unsigned int input);
+
static int terratec_active_radio_upgrade(struct bttv *btv);
static int tea5757_read(struct bttv *btv);
static int tea5757_write(struct bttv *btv, int value);
@@ -284,7 +286,8 @@ static struct CARD {
{ 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" },
{ 0x217d6606, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" },
{ 0xfff6f6ff, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" },
- { 0x03116000, BTTV_BOARD_SENSORAY311, "Sensoray 311" },
+ { 0x03116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 311" },
+ { 0x06116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 611" },
{ 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" },
{ 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" },
{ 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
@@ -341,6 +344,7 @@ static struct CARD {
{ 0x15401835, BTTV_BOARD_PV183, "Provideo PV183-6" },
{ 0x15401836, BTTV_BOARD_PV183, "Provideo PV183-7" },
{ 0x15401837, BTTV_BOARD_PV183, "Provideo PV183-8" },
+ { 0x3116f200, BTTV_BOARD_TVT_TD3116, "Tongwei Video Technology TD-3116" },
{ 0, -1, NULL }
};
@@ -1526,10 +1530,10 @@ struct tvcard bttv_tvcards[] = {
GPIO20,22,23: R30,R29,R28
*/
},
- [BTTV_BOARD_SENSORAY311] = {
+ [BTTV_BOARD_SENSORAY311_611] = {
/* Clay Kunz <ckunz@mail.arc.nasa.gov> */
- /* you must jumper JP5 for the card to work */
- .name = "Sensoray 311",
+ /* you must jumper JP5 for the 311 card (PC/104+) to work */
+ .name = "Sensoray 311/611",
.video_inputs = 5,
/* .audio_inputs= 0, */
.svhs = 4,
@@ -2879,6 +2883,16 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
},
+ [BTTV_BOARD_TVT_TD3116] = {
+ .name = "Tongwei Video Technology TD-3116",
+ .video_inputs = 16,
+ .gpiomask = 0xc00ff,
+ .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
+ .muxsel_hook = td3116_muxsel,
+ .svhs = NO_SVHS,
+ .pll = PLL_28,
+ .tuner_type = TUNER_ABSENT,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3228,6 +3242,42 @@ static void geovision_muxsel(struct bttv *btv, unsigned int input)
gpio_bits(0xf, inmux);
}
+/*
+ * The TD3116 has 2 74HC4051 muxes wired to the MUX0 input of a bt878.
+ * The first 74HC4051 has the lower 8 inputs, the second one the higher 8.
+ * The muxes are controlled via a 74HC373 latch which is connected to
+ * GPIOs 0-7. GPIO 18 is connected to the LE signal of the latch.
+ * Q0 of the latch is connected to the Enable (~E) input of the first
+ * 74HC4051. Q1 - Q3 are connected to S0 - S2 of the same 74HC4051.
+ * Q4 - Q7 are connected to the second 74HC4051 in the same way.
+ */
+
+static void td3116_latch_value(struct bttv *btv, u32 value)
+{
+ gpio_bits((1<<18) | 0xff, value);
+ gpio_bits((1<<18) | 0xff, (1<<18) | value);
+ udelay(1);
+ gpio_bits((1<<18) | 0xff, value);
+}
+
+static void td3116_muxsel(struct bttv *btv, unsigned int input)
+{
+ u32 value;
+ u32 highbit;
+
+ highbit = (input & 0x8) >> 3 ;
+
+ /* Disable outputs and set value in the mux */
+ value = 0x11; /* Disable outputs */
+ value |= ((input & 0x7) << 1) << (4 * highbit);
+ td3116_latch_value(btv, value);
+
+ /* Enable the correct output */
+ value &= ~0x11;
+ value |= ((highbit ^ 0x1) << 4) | highbit;
+ td3116_latch_value(btv, value);
+}
+
/* ----------------------------------------------------------------------- */
static void bttv_reset_audio(struct bttv *btv)
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 3dd06607aec2..e581b37be789 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2035,11 +2035,7 @@ static int bttv_log_status(struct file *file, void *f)
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
- pr_info("%d: ======== START STATUS CARD #%d ========\n",
- btv->c.nr, btv->c.nr);
bttv_call_all(btv, core, log_status);
- pr_info("%d: ======== END STATUS CARD #%d ========\n",
- btv->c.nr, btv->c.nr);
return 0;
}
@@ -4572,6 +4568,7 @@ static struct pci_device_id bttv_pci_tbl[] = {
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0},
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0},
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0},
+ {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879), 0},
{0,}
};
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index e3952af7e56e..580c8e682392 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -346,7 +346,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
}
}
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
int __devinit init_bttv_i2c(struct bttv *btv)
{
strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index c6333595c6b9..c5171619ac79 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -96,7 +96,7 @@
#define BTTV_BOARD_PV_BT878P_PLUS 0x46
#define BTTV_BOARD_FLYVIDEO98EZ 0x47
#define BTTV_BOARD_PV_BT878P_9B 0x48
-#define BTTV_BOARD_SENSORAY311 0x49
+#define BTTV_BOARD_SENSORAY311_611 0x49
#define BTTV_BOARD_RV605 0x4a
#define BTTV_BOARD_POWERCLR_MTV878 0x4b
#define BTTV_BOARD_WINDVR 0x4c
@@ -183,6 +183,7 @@
#define BTTV_BOARD_GEOVISION_GV800S 0x9d
#define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e
#define BTTV_BOARD_PV183 0x9f
+#define BTTV_BOARD_TVT_TD3116 0xa0
/* more card-specific defines */
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index cd8ff0473184..fda32f52554a 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -72,7 +72,7 @@ struct qcam {
static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
static int probe = 2;
-static int force_rgb;
+static bool force_rgb;
static int video_nr = -1;
/* FIXME: parport=auto would never have worked, surely? --RR */
diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
index 5909f2557ab4..c8581e26fa9c 100644
--- a/drivers/media/video/cs5345.c
+++ b/drivers/media/video/cs5345.c
@@ -31,7 +31,7 @@ MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
MODULE_AUTHOR("Hans Verkuil");
MODULE_LICENSE("GPL");
-static int debug;
+static bool debug;
module_param(debug, bool, 0644);
@@ -249,15 +249,4 @@ static struct i2c_driver cs5345_driver = {
.id_table = cs5345_id,
};
-static __init int init_cs5345(void)
-{
- return i2c_add_driver(&cs5345_driver);
-}
-
-static __exit void exit_cs5345(void)
-{
- i2c_del_driver(&cs5345_driver);
-}
-
-module_init(init_cs5345);
-module_exit(exit_cs5345);
+module_i2c_driver(cs5345_driver);
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index d93e5ab45fd3..b293912206eb 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -35,7 +35,7 @@ MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
MODULE_AUTHOR("Martin Vaughan");
MODULE_LICENSE("GPL");
-static int debug;
+static bool debug;
module_param(debug, bool, 0644);
@@ -248,15 +248,4 @@ static struct i2c_driver cs53l32a_driver = {
.id_table = cs53l32a_id,
};
-static __init int init_cs53l32a(void)
-{
- return i2c_add_driver(&cs53l32a_driver);
-}
-
-static __exit void exit_cs53l32a(void)
-{
- i2c_del_driver(&cs53l32a_driver);
-}
-
-module_init(init_cs53l32a);
-module_exit(exit_cs53l32a);
+module_i2c_driver(cs53l32a_driver);
diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c
index a1e6c2a32478..e118361c2e7b 100644
--- a/drivers/media/video/cx18/cx18-alsa-main.c
+++ b/drivers/media/video/cx18/cx18-alsa-main.c
@@ -285,7 +285,6 @@ static void __exit cx18_alsa_exit(void)
drv = driver_find("cx18", &pci_bus_type);
ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
- put_driver(drv);
cx18_ext_init = NULL;
printk(KERN_INFO "cx18-alsa: module unload complete\n");
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index c6ff32a6137c..b55d57cc1a1c 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -38,7 +38,7 @@
#include "cx18-ioctl.h"
#include "cx18-controls.h"
#include "tuner-xc2028.h"
-
+#include <linux/dma-mapping.h>
#include <media/tveeprom.h>
/* If you have already X v4l cards, then set this to X. This way
@@ -110,7 +110,7 @@ static int retry_mmio = 1;
int cx18_debug;
module_param_array(tuner, int, &tuner_c, 0644);
-module_param_array(radio, bool, &radio_c, 0644);
+module_param_array(radio, int, &radio_c, 0644);
module_param_array(cardtype, int, &cardtype_c, 0644);
module_param_string(pal, pal, sizeof(pal), 0644);
module_param_string(secam, secam, sizeof(secam), 0644);
@@ -812,7 +812,7 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
CX18_ERR("Can't enable device %d!\n", cx->instance);
return -EIO;
}
- if (pci_set_dma_mask(pci_dev, 0xffffffff)) {
+ if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) {
CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
return -EIO;
}
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index b9a94fc5146d..7a37e0ee136f 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -44,8 +44,6 @@
#include <linux/slab.h>
#include <asm/byteorder.h>
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index 14cb961c22bd..4bfd865a4106 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -751,20 +751,10 @@ int cx18_v4l2_close(struct file *filp)
CX18_DEBUG_IOCTL("close() of %s\n", s->name);
- v4l2_fh_del(fh);
- v4l2_fh_exit(fh);
-
- /* Easy case first: this stream was never claimed by us */
- if (s->id != id->open_id) {
- kfree(id);
- return 0;
- }
-
- /* 'Unclaim' this stream */
-
- /* Stop radio */
mutex_lock(&cx->serialize_lock);
- if (id->type == CX18_ENC_STREAM_TYPE_RAD) {
+ /* Stop radio */
+ if (id->type == CX18_ENC_STREAM_TYPE_RAD &&
+ v4l2_fh_is_singular_file(filp)) {
/* Closing radio device, return to TV mode */
cx18_mute(cx);
/* Mark that the radio is no longer in use */
@@ -781,10 +771,14 @@ int cx18_v4l2_close(struct file *filp)
}
/* Done! Unmute and continue. */
cx18_unmute(cx);
- cx18_release_stream(s);
- } else {
- cx18_stop_capture(id, 0);
}
+
+ v4l2_fh_del(fh);
+ v4l2_fh_exit(fh);
+
+ /* 'Unclaim' this stream */
+ if (s->id == id->open_id)
+ cx18_stop_capture(id, 0);
kfree(id);
mutex_unlock(&cx->serialize_lock);
return 0;
@@ -810,21 +804,15 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
item->open_id = cx->open_id++;
filp->private_data = &item->fh;
+ v4l2_fh_add(&item->fh);
- if (item->type == CX18_ENC_STREAM_TYPE_RAD) {
- /* Try to claim this stream */
- if (cx18_claim_stream(item, item->type)) {
- /* No, it's already in use */
- v4l2_fh_exit(&item->fh);
- kfree(item);
- return -EBUSY;
- }
-
+ if (item->type == CX18_ENC_STREAM_TYPE_RAD &&
+ v4l2_fh_is_singular_file(filp)) {
if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
if (atomic_read(&cx->ana_capturing) > 0) {
/* switching to radio while capture is
in progress is not polite */
- cx18_release_stream(s);
+ v4l2_fh_del(&item->fh);
v4l2_fh_exit(&item->fh);
kfree(item);
return -EBUSY;
@@ -842,7 +830,6 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
/* Done! Unmute and continue. */
cx18_unmute(cx);
}
- v4l2_fh_add(&item->fh);
return 0;
}
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 040aaa87579d..51609d5c88ce 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -232,7 +232,7 @@ static struct i2c_algo_bit_data cx18_i2c_algo_template = {
.timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
};
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
int init_cx18_i2c(struct cx18 *cx)
{
int i, err;
diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h
index bdfd1921e300..1180fdc8d983 100644
--- a/drivers/media/video/cx18/cx18-i2c.h
+++ b/drivers/media/video/cx18/cx18-i2c.h
@@ -24,6 +24,6 @@
int cx18_i2c_register(struct cx18 *cx, unsigned idx);
struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw);
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
int init_cx18_i2c(struct cx18 *cx);
void exit_cx18_i2c(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 66b1c15c3541..be49f68ddf37 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -1085,8 +1085,6 @@ static int cx18_log_status(struct file *file, void *fh)
struct v4l2_audio audin;
int i;
- CX18_INFO("================= START STATUS CARD #%d "
- "=================\n", cx->instance);
CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name);
if (cx->hw_flags & CX18_HW_TVEEPROM) {
struct tveeprom tv;
@@ -1120,8 +1118,6 @@ static int cx18_log_status(struct file *file, void *fh)
CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
(long long)cx->mpg_data_received,
(long long)cx->vbi_data_inserted);
- CX18_INFO("================== END STATUS CARD #%d "
- "==================\n", cx->instance);
return 0;
}
diff --git a/drivers/media/video/cx231xx/Kconfig b/drivers/media/video/cx231xx/Kconfig
index ae85a7a7bd73..446f692aabb7 100644
--- a/drivers/media/video/cx231xx/Kconfig
+++ b/drivers/media/video/cx231xx/Kconfig
@@ -40,10 +40,10 @@ config VIDEO_CX231XX_ALSA
config VIDEO_CX231XX_DVB
tristate "DVB/ATSC Support for Cx231xx based TV cards"
- depends on VIDEO_CX231XX && DVB_CORE
+ depends on VIDEO_CX231XX && DVB_CORE && DVB_CAPTURE_DRIVERS
select VIDEOBUF_DVB
- select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE
- select MEDIA_TUNER_NXP18271 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
select DVB_MB86A20S if !DVB_FE_CUSTOMISE
---help---
diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c
index f8f0e59cd583..d4327dab5a36 100644
--- a/drivers/media/video/cx231xx/cx231xx-417.c
+++ b/drivers/media/video/cx231xx/cx231xx-417.c
@@ -1686,7 +1686,6 @@ static struct v4l2_capability pvr_capability = {
.capabilities = (V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
- .reserved = {0, 0, 0, 0}
};
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c
index 30d13c15739a..a2c2b7d343ec 100644
--- a/drivers/media/video/cx231xx/cx231xx-audio.c
+++ b/drivers/media/video/cx231xx/cx231xx-audio.c
@@ -111,6 +111,9 @@ static void cx231xx_audio_isocirq(struct urb *urb)
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
+ if (dev->state & DEV_DISCONNECTED)
+ return;
+
switch (urb->status) {
case 0: /* success */
case -ETIMEDOUT: /* NAK */
@@ -196,6 +199,9 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
+ if (dev->state & DEV_DISCONNECTED)
+ return;
+
switch (urb->status) {
case 0: /* success */
case -ETIMEDOUT: /* NAK */
@@ -273,6 +279,9 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__);
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+
sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
@@ -298,7 +307,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
urb->context = dev;
urb->pipe = usb_rcvisocpipe(dev->udev,
dev->adev.end_point_addr);
- urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
urb->transfer_buffer = dev->adev.transfer_buffer[i];
urb->interval = 1;
urb->complete = cx231xx_audio_isocirq;
@@ -331,6 +340,9 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev)
cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__);
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+
sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
@@ -356,7 +368,7 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev)
urb->context = dev;
urb->pipe = usb_rcvbulkpipe(dev->udev,
dev->adev.end_point_addr);
- urb->transfer_flags = 0;
+ urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
urb->transfer_buffer = dev->adev.transfer_buffer[i];
urb->complete = cx231xx_audio_bulkirq;
urb->transfer_buffer_length = sb_size;
@@ -432,6 +444,11 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
return -ENODEV;
}
+ if (dev->state & DEV_DISCONNECTED) {
+ cx231xx_errdev("Can't open. the device was removed.\n");
+ return -ENODEV;
+ }
+
/* Sets volume, mute, etc */
dev->mute = 0;
@@ -571,6 +588,9 @@ static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
struct cx231xx *dev = snd_pcm_substream_chip(substream);
int retval;
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+
spin_lock(&dev->adev.slock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c
index 60b021e79864..8ed460d692e0 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -843,25 +843,33 @@ void cx231xx_release_resources(struct cx231xx *dev)
cx231xx_remove_from_devlist(dev);
+ cx231xx_ir_exit(dev);
+
/* Release I2C buses */
cx231xx_dev_uninit(dev);
- cx231xx_ir_exit(dev);
+ /* delete v4l2 device */
+ v4l2_device_unregister(&dev->v4l2_dev);
usb_put_dev(dev->udev);
/* Mark device as unused */
- cx231xx_devused &= ~(1 << dev->devno);
+ clear_bit(dev->devno, &cx231xx_devused);
+
+ kfree(dev->video_mode.alt_max_pkt_size);
+ kfree(dev->vbi_mode.alt_max_pkt_size);
+ kfree(dev->sliced_cc_mode.alt_max_pkt_size);
+ kfree(dev->ts1_mode.alt_max_pkt_size);
+ kfree(dev);
}
/*
* cx231xx_init_dev()
* allocates and inits the device structs, registers i2c bus and v4l device
*/
-static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
+static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
int minor)
{
- struct cx231xx *dev = *devhandle;
int retval = -ENOMEM;
int errCode;
unsigned int maxh, maxw;
@@ -1016,7 +1024,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
int i, isoc_pipe = 0;
char *speed;
char descr[255] = "";
- struct usb_interface *lif = NULL;
struct usb_interface_assoc_descriptor *assoc_desc;
udev = usb_get_dev(interface_to_usbdev(interface));
@@ -1030,21 +1037,21 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
return -ENODEV;
/* Check to see next free device and mark as used */
- nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS);
- cx231xx_devused |= 1 << nr;
-
- if (nr >= CX231XX_MAXBOARDS) {
- cx231xx_err(DRIVER_NAME
- ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS);
- cx231xx_devused &= ~(1 << nr);
- return -ENOMEM;
- }
+ do {
+ nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS);
+ if (nr >= CX231XX_MAXBOARDS) {
+ /* No free device slots */
+ cx231xx_err(DRIVER_NAME ": Supports only %i devices.\n",
+ CX231XX_MAXBOARDS);
+ return -ENOMEM;
+ }
+ } while (test_and_set_bit(nr, &cx231xx_devused));
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
cx231xx_err(DRIVER_NAME ": out of memory!\n");
- cx231xx_devused &= ~(1 << nr);
+ clear_bit(nr, &cx231xx_devused);
return -ENOMEM;
}
@@ -1071,9 +1078,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* init CIR module TBD */
- /* store the current interface */
- lif = interface;
-
/*mode_tv: digital=1 or analog=0*/
dev->mode_tv = 0;
@@ -1113,9 +1117,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
le16_to_cpu(udev->descriptor.idProduct),
dev->max_iad_interface_count);
- /* store the interface 0 back */
- lif = udev->actconfig->interface[0];
-
/* increment interface count */
dev->interface_count++;
@@ -1126,7 +1127,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
if (assoc_desc->bFirstInterface != ifnum) {
cx231xx_err(DRIVER_NAME ": Not found "
"matching IAD interface\n");
- cx231xx_devused &= ~(1 << nr);
+ clear_bit(dev->devno, &cx231xx_devused);
kfree(dev);
dev = NULL;
return -ENODEV;
@@ -1135,7 +1136,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
cx231xx_info("registering interface %d\n", ifnum);
/* save our data pointer in this interface device */
- usb_set_intfdata(lif, dev);
+ usb_set_intfdata(interface, dev);
/*
* AV device initialization - only done at the last interface
@@ -1145,19 +1146,19 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
cx231xx_errdev("v4l2_device_register failed\n");
- cx231xx_devused &= ~(1 << nr);
+ clear_bit(dev->devno, &cx231xx_devused);
kfree(dev);
dev = NULL;
return -EIO;
}
/* allocate device struct */
- retval = cx231xx_init_dev(&dev, udev, nr);
+ retval = cx231xx_init_dev(dev, udev, nr);
if (retval) {
- cx231xx_devused &= ~(1 << dev->devno);
+ clear_bit(dev->devno, &cx231xx_devused);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
dev = NULL;
- usb_set_intfdata(lif, NULL);
+ usb_set_intfdata(interface, NULL);
return retval;
}
@@ -1178,7 +1179,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
if (dev->video_mode.alt_max_pkt_size == NULL) {
cx231xx_errdev("out of memory!\n");
- cx231xx_devused &= ~(1 << nr);
+ clear_bit(dev->devno, &cx231xx_devused);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
dev = NULL;
@@ -1212,7 +1213,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
if (dev->vbi_mode.alt_max_pkt_size == NULL) {
cx231xx_errdev("out of memory!\n");
- cx231xx_devused &= ~(1 << nr);
+ clear_bit(dev->devno, &cx231xx_devused);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
dev = NULL;
@@ -1247,7 +1248,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) {
cx231xx_errdev("out of memory!\n");
- cx231xx_devused &= ~(1 << nr);
+ clear_bit(dev->devno, &cx231xx_devused);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
dev = NULL;
@@ -1283,7 +1284,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
if (dev->ts1_mode.alt_max_pkt_size == NULL) {
cx231xx_errdev("out of memory!\n");
- cx231xx_devused &= ~(1 << nr);
+ clear_bit(dev->devno, &cx231xx_devused);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
dev = NULL;
@@ -1334,10 +1335,9 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
if (!dev->udev)
return;
- flush_request_modules(dev);
+ dev->state |= DEV_DISCONNECTED;
- /* delete v4l2 device */
- v4l2_device_unregister(&dev->v4l2_dev);
+ flush_request_modules(dev);
/* wait until all current v4l2 io is finished then deallocate
resources */
@@ -1351,31 +1351,24 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
"deallocation are deferred on close.\n",
video_device_node_name(dev->vdev));
- dev->state |= DEV_MISCONFIGURED;
+ /* Even having users, it is safe to remove the RC i2c driver */
+ cx231xx_ir_exit(dev);
+
if (dev->USE_ISO)
cx231xx_uninit_isoc(dev);
else
cx231xx_uninit_bulk(dev);
- dev->state |= DEV_DISCONNECTED;
wake_up_interruptible(&dev->wait_frame);
wake_up_interruptible(&dev->wait_stream);
} else {
- dev->state |= DEV_DISCONNECTED;
- cx231xx_release_resources(dev);
}
cx231xx_close_extension(dev);
mutex_unlock(&dev->lock);
- if (!dev->users) {
- kfree(dev->video_mode.alt_max_pkt_size);
- kfree(dev->vbi_mode.alt_max_pkt_size);
- kfree(dev->sliced_cc_mode.alt_max_pkt_size);
- kfree(dev->ts1_mode.alt_max_pkt_size);
- kfree(dev);
- dev = NULL;
- }
+ if (!dev->users)
+ cx231xx_release_resources(dev);
}
static struct usb_driver cx231xx_usb_driver = {
diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c
index d4457f9488ee..08dd930f882a 100644
--- a/drivers/media/video/cx231xx/cx231xx-core.c
+++ b/drivers/media/video/cx231xx/cx231xx-core.c
@@ -166,6 +166,9 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
u8 _i2c_nostop = 0;
u8 _i2c_reserve = 0;
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+
/* Get the I2C period, nostop and reserve parameters */
_i2c_period = i2c_bus->i2c_period;
_i2c_nostop = i2c_bus->i2c_nostop;
@@ -1071,7 +1074,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
sb_size, cx231xx_isoc_irq_callback, dma_q, 1);
urb->number_of_packets = max_packets;
- urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
k = 0;
for (j = 0; j < max_packets; j++) {
@@ -1182,7 +1185,7 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
return -ENOMEM;
}
dev->video_mode.bulk_ctl.urb[i] = urb;
- urb->transfer_flags = 0;
+ urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
dev->video_mode.bulk_ctl.transfer_buffer[i] =
usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL,
diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c
index da9a4a0aab79..7c4e360ba9bc 100644
--- a/drivers/media/video/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/video/cx231xx/cx231xx-dvb.c
@@ -196,7 +196,7 @@ static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb)
if (!dev)
return 0;
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ if (dev->state & DEV_DISCONNECTED)
return 0;
if (urb->status < 0) {
@@ -228,7 +228,7 @@ static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb)
if (!dev)
return 0;
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ if (dev->state & DEV_DISCONNECTED)
return 0;
if (urb->status < 0) {
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c
index 45e14cac4622..96176e9db5a2 100644
--- a/drivers/media/video/cx231xx/cx231xx-input.c
+++ b/drivers/media/video/cx231xx/cx231xx-input.c
@@ -27,12 +27,16 @@
static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw)
{
+ int rc;
u8 cmd, scancode;
dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__);
/* poll IR chip */
- if (1 != i2c_master_recv(ir->c, &cmd, 1))
+ rc = i2c_master_recv(ir->c, &cmd, 1);
+ if (rc < 0)
+ return rc;
+ if (rc != 1)
return -EIO;
/* it seems that 0xFE indicates that a button is still hold
@@ -102,11 +106,14 @@ int cx231xx_ir_init(struct cx231xx *dev)
ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master;
dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n",
ir_i2c_bus, info.addr);
- i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info);
+ dev->ir_i2c_client = i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info);
return 0;
}
void cx231xx_ir_exit(struct cx231xx *dev)
{
+ if (dev->ir_i2c_client)
+ i2c_unregister_device(dev->ir_i2c_client);
+ dev->ir_i2c_client = NULL;
}
diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c
index 1c7a4daafecf..8cdee5f78f13 100644
--- a/drivers/media/video/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/video/cx231xx/cx231xx-vbi.c
@@ -93,7 +93,7 @@ static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb)
if (!dev)
return 0;
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ if (dev->state & DEV_DISCONNECTED)
return 0;
if (urb->status < 0) {
@@ -452,7 +452,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
return -ENOMEM;
}
dev->vbi_mode.bulk_ctl.urb[i] = urb;
- urb->transfer_flags = 0;
+ urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
kzalloc(sb_size, GFP_KERNEL);
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index 6e81f970dc7d..7f916f0685e9 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -337,7 +337,7 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
if (!dev)
return 0;
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ if (dev->state & DEV_DISCONNECTED)
return 0;
if (urb->status < 0) {
@@ -440,7 +440,7 @@ static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
if (!dev)
return 0;
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ if (dev->state & DEV_DISCONNECTED)
return 0;
if (urb->status < 0) {
@@ -1000,12 +1000,6 @@ static int check_dev(struct cx231xx *dev)
cx231xx_errdev("v4l2 ioctl: device not present\n");
return -ENODEV;
}
-
- if (dev->state & DEV_MISCONFIGURED) {
- cx231xx_errdev("v4l2 ioctl: device is misconfigured; "
- "close and open it again\n");
- return -EIO;
- }
return 0;
}
@@ -2325,8 +2319,7 @@ static int cx231xx_v4l2_close(struct file *filp)
if (dev->state & DEV_DISCONNECTED) {
if (atomic_read(&dev->devlist_count) > 0) {
cx231xx_release_resources(dev);
- kfree(dev);
- dev = NULL;
+ fh->dev = NULL;
return 0;
}
return 0;
@@ -2347,7 +2340,8 @@ static int cx231xx_v4l2_close(struct file *filp)
return 0;
}
- if (dev->users == 1) {
+ dev->users--;
+ if (!dev->users) {
videobuf_stop(&fh->vb_vidq);
videobuf_mmap_free(&fh->vb_vidq);
@@ -2355,8 +2349,7 @@ static int cx231xx_v4l2_close(struct file *filp)
free the remaining resources */
if (dev->state & DEV_DISCONNECTED) {
cx231xx_release_resources(dev);
- kfree(dev);
- dev = NULL;
+ fh->dev = NULL;
return 0;
}
@@ -2374,7 +2367,6 @@ static int cx231xx_v4l2_close(struct file *filp)
cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
}
kfree(fh);
- dev->users--;
wake_up_interruptible_nr(&dev->open, 1);
return 0;
}
diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h
index 2000bc64c497..e17447554a0d 100644
--- a/drivers/media/video/cx231xx/cx231xx.h
+++ b/drivers/media/video/cx231xx/cx231xx.h
@@ -377,7 +377,6 @@ struct cx231xx_board {
enum cx231xx_dev_state {
DEV_INITIALIZED = 0x01,
DEV_DISCONNECTED = 0x02,
- DEV_MISCONFIGURED = 0x04,
};
enum AFE_MODE {
@@ -621,6 +620,7 @@ struct cx231xx {
/* For I2C IR support */
struct IR_i2c_init_data init_data;
+ struct i2c_client *ir_i2c_client;
unsigned int stream_on:1; /* Locks streams */
unsigned int vbi_stream_on:1; /* Locks streams for VBI */
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index 67c4a59bd882..f5c79e53e5a1 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -900,6 +900,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
int i, retval = 0;
u32 value = 0;
u32 gpio_output = 0;
+ u32 gpio_value;
u32 checksum = 0;
u32 *dataptr;
@@ -907,7 +908,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
/* Save GPIO settings before reset of APU */
retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
- retval |= mc417_memory_read(dev, 0x900C, &value);
+ retval |= mc417_memory_read(dev, 0x900C, &gpio_value);
retval = mc417_register_write(dev,
IVTV_REG_VPU, 0xFFFFFFED);
@@ -991,11 +992,18 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
/* F/W power up disturbs the GPIOs, restore state */
retval |= mc417_register_write(dev, 0x9020, gpio_output);
- retval |= mc417_register_write(dev, 0x900C, value);
+ retval |= mc417_register_write(dev, 0x900C, gpio_value);
retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
+ /* Hardcoded GPIO's here */
+ retval |= mc417_register_write(dev, 0x9020, 0x4000);
+ retval |= mc417_register_write(dev, 0x900C, 0x4000);
+
+ mc417_register_read(dev, 0x9020, &gpio_output);
+ mc417_register_read(dev, 0x900C, &gpio_value);
+
if (retval < 0)
printk(KERN_ERR "%s: Error with mc417_register_write\n",
__func__);
@@ -1015,6 +1023,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev)
{
dprintk(1, "%s()\n", __func__);
+ /* Dynamically change the height based on video standard */
+ if (dev->encodernorm.id & V4L2_STD_525_60)
+ dev->ts1.height = 480;
+ else
+ dev->ts1.height = 576;
+
/* assign frame size */
cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
dev->ts1.height, dev->ts1.width);
@@ -1030,7 +1044,7 @@ static void cx23885_codec_settings(struct cx23885_dev *dev)
cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
}
-static int cx23885_initialize_codec(struct cx23885_dev *dev)
+static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
{
int version;
int retval;
@@ -1112,9 +1126,11 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev)
mc417_memory_write(dev, 2120, 0x00000080);
/* start capturing to the host interface */
- cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
- CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
- msleep(10);
+ if (startencoder) {
+ cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+ CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
+ msleep(10);
+ }
return 0;
}
@@ -1196,6 +1212,16 @@ static int cx23885_querymenu(struct cx23885_dev *dev,
cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ call_all(dev, core, g_std, id);
+
+ return 0;
+}
+
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
{
struct cx23885_fh *fh = file->private_data;
@@ -1208,55 +1234,31 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
if (i == ARRAY_SIZE(cx23885_tvnorms))
return -EINVAL;
dev->encodernorm = cx23885_tvnorms[i];
+
+ /* Have the drier core notify the subdevices */
+ mutex_lock(&dev->lock);
+ cx23885_set_tvnorm(dev, *id);
+ mutex_unlock(&dev->lock);
+
return 0;
}
static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
+ struct v4l2_input *i)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
- struct cx23885_input *input;
- int n;
-
- if (i->index >= 4)
- return -EINVAL;
-
- input = &cx23885_boards[dev->board].input[i->index];
-
- if (input->type == 0)
- return -EINVAL;
-
- /* FIXME
- * strcpy(i->name, input->name); */
- strcpy(i->name, "unset");
-
- if (input->type == CX23885_VMUX_TELEVISION ||
- input->type == CX23885_VMUX_CABLE)
- i->type = V4L2_INPUT_TYPE_TUNER;
- else
- i->type = V4L2_INPUT_TYPE_CAMERA;
-
- for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++)
- i->std |= cx23885_tvnorms[n].id;
- return 0;
+ struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ dprintk(1, "%s()\n", __func__);
+ return cx23885_enum_input(dev, i);
}
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- *i = dev->input;
- return 0;
+ return cx23885_get_input(file, priv, i);
}
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
- if (i >= 4)
- return -EINVAL;
-
- return 0;
+ return cx23885_set_input(file, priv, i);
}
static int vidioc_g_tuner(struct file *file, void *priv,
@@ -1309,43 +1311,25 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ struct v4l2_frequency *f)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
- CX23885_END_NOW, CX23885_MPEG_CAPTURE,
- CX23885_RAW_BITS_NONE);
-
- dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n",
- dev->tuner_type);
- dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n",
- f->tuner, f->type);
- if (UNSET == dev->tuner_type)
- return -EINVAL;
- if (f->tuner != 0)
- return -EINVAL;
- if (f->type != V4L2_TUNER_ANALOG_TV)
- return -EINVAL;
- dev->freq = f->frequency;
-
- call_all(dev, tuner, s_frequency, f);
+ return cx23885_set_frequency(file, priv, f);
+}
- cx23885_initialize_codec(dev);
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- return 0;
+ return cx23885_get_control(dev, ctl);
}
static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
+ struct v4l2_control *ctl)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- /* Update the A/V core */
- call_all(dev, core, s_ctrl, ctl);
- return 0;
+ return cx23885_set_control(dev, ctl);
}
static int vidioc_querycap(struct file *file, void *priv,
@@ -1636,7 +1620,7 @@ static ssize_t mpeg_read(struct file *file, char __user *data,
/* Start mpeg encoder on first read. */
if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
- if (cx23885_initialize_codec(dev) < 0)
+ if (cx23885_initialize_codec(dev, 1) < 0)
return -EINVAL;
}
}
@@ -1677,6 +1661,8 @@ static struct v4l2_file_operations mpeg_fops = {
};
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+ .vidioc_querystd = vidioc_g_std,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
@@ -1686,6 +1672,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
@@ -1746,8 +1733,8 @@ static struct video_device *cx23885_video_dev_alloc(
if (NULL == vfd)
return NULL;
*vfd = *template;
- snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
- type, cx23885_boards[tsport->dev->board].name);
+ snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
+ cx23885_boards[tsport->dev->board].name, type);
vfd->parent = &pci->dev;
vfd->release = video_device_release;
return vfd;
@@ -1791,5 +1778,11 @@ int cx23885_417_register(struct cx23885_dev *dev)
printk(KERN_INFO "%s: registered device %s [mpeg]\n",
dev->name, video_device_node_name(dev->v4l_device));
+ /* ST: Configure the encoder paramaters, but don't begin
+ * encoding, this resolves an issue where the first time the
+ * encoder is started video can be choppy.
+ */
+ cx23885_initialize_codec(dev, 0);
+
return 0;
}
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index c3cf08945e4c..19b5499d2624 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -213,8 +213,8 @@ struct cx23885_board cx23885_boards[] = {
.portc = CX23885_MPEG_DVB,
.tuner_type = TUNER_XC4000,
.tuner_addr = 0x61,
- .radio_type = TUNER_XC4000,
- .radio_addr = 0x61,
+ .radio_type = UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX23885_VMUX_TELEVISION,
.vmux = CX25840_VIN2_CH1 |
@@ -335,8 +335,33 @@ struct cx23885_board cx23885_boards[] = {
},
[CX23885_BOARD_HAUPPAUGE_HVR1850] = {
.name = "Hauppauge WinTV-HVR1850",
+ .porta = CX23885_ANALOG_VIDEO,
.portb = CX23885_MPEG_ENCODER,
.portc = CX23885_MPEG_DVB,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = 0x42, /* 0x84 >> 1 */
+ .force_bff = 1,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN5_CH2 |
+ CX25840_VIN2_CH1 |
+ CX25840_DIF_ON,
+ .amux = CX25840_AUDIO8,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN6_CH1,
+ .amux = CX25840_AUDIO7,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
+ } },
},
[CX23885_BOARD_COMPRO_VIDEOMATE_E800] = {
.name = "Compro VideoMate E800",
@@ -438,6 +463,41 @@ struct cx23885_board cx23885_boards[] = {
.gpio0 = 0,
} },
},
+ [CX23885_BOARD_MYGICA_X8507] = {
+ .name = "Mygica X8507",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ .tuner_bus = 1,
+ .porta = CX23885_ANALOG_VIDEO,
+ .input = {
+ {
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_COMPOSITE2,
+ .amux = CX25840_AUDIO8,
+ },
+ {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_COMPOSITE8,
+ },
+ {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_SVIDEO_LUMA3 |
+ CX25840_SVIDEO_CHROMA4,
+ },
+ {
+ .type = CX23885_VMUX_COMPONENT,
+ .vmux = CX25840_COMPONENT_ON |
+ CX25840_VIN1_CH1 |
+ CX25840_VIN6_CH2 |
+ CX25840_VIN7_CH3,
+ },
+ },
+ },
+ [CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL] = {
+ .name = "TerraTec Cinergy T PCIe Dual",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ }
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -637,6 +697,14 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x1b55,
.subdevice = 0xe2e4,
.card = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF,
+ }, {
+ .subvendor = 0x14f1,
+ .subdevice = 0x8502,
+ .card = CX23885_BOARD_MYGICA_X8507,
+ }, {
+ .subvendor = 0x153b,
+ .subdevice = 0x117e,
+ .card = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1068,6 +1136,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
break;
case CX23885_BOARD_MYGICA_X8506:
case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+ case CX23885_BOARD_MYGICA_X8507:
/* GPIO-0 (0)Analog / (1)Digital TV */
/* GPIO-1 reset XC5000 */
/* GPIO-2 reset LGS8GL5 / LGS8G75 */
@@ -1367,6 +1436,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1800:
/* Defaults for VID B - Analog encoder */
/* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */
@@ -1377,6 +1447,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
/* APB_TSVALERR_POL (active low)*/
ts1->vld_misc_val = 0x2000;
ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc);
+ cx_write(0x130184, 0xc);
/* Defaults for VID C */
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
@@ -1396,6 +1467,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
break;
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+ case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -1431,7 +1503,6 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
@@ -1468,6 +1539,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_MPX885:
+ case CX23885_BOARD_MYGICA_X8507:
+ case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
"cx25840", 0x88 >> 1, NULL);
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 40e68b22015e..6ad227029a0f 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -206,12 +206,12 @@ static struct sram_channel cx23887_sram_channels[] = {
.cnt2_reg = DMA1_CNT2,
},
[SRAM_CH02] = {
- .name = "ch2",
- .cmds_start = 0x0,
- .ctrl_start = 0x0,
- .cdt = 0x0,
- .fifo_start = 0x0,
- .fifo_size = 0x0,
+ .name = "VID A (VBI)",
+ .cmds_start = 0x10050,
+ .ctrl_start = 0x105F0,
+ .cdt = 0x10810,
+ .fifo_start = 0x3000,
+ .fifo_size = 0x1000,
.ptr1_reg = DMA2_PTR1,
.ptr2_reg = DMA2_PTR2,
.cnt1_reg = DMA2_CNT1,
@@ -266,12 +266,12 @@ static struct sram_channel cx23887_sram_channels[] = {
.cnt2_reg = DMA5_CNT2,
},
[SRAM_CH07] = {
- .name = "ch7",
- .cmds_start = 0x0,
- .ctrl_start = 0x0,
- .cdt = 0x0,
- .fifo_start = 0x0,
- .fifo_size = 0x0,
+ .name = "TV Audio",
+ .cmds_start = 0x10190,
+ .ctrl_start = 0x106B0,
+ .cdt = 0x10930,
+ .fifo_start = 0x7000,
+ .fifo_size = 0x1000,
.ptr1_reg = DMA6_PTR1,
.ptr2_reg = DMA6_PTR2,
.cnt1_reg = DMA6_CNT1,
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index bcb45be44bb2..6835eb1fc093 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -61,6 +61,8 @@
#include "cx23885-f300.h"
#include "altera-ci.h"
#include "stv0367.h"
+#include "drxk.h"
+#include "mt2063.h"
static unsigned int debug;
@@ -111,6 +113,8 @@ static void dvb_buf_release(struct videobuf_queue *q,
cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
}
+static int cx23885_dvb_set_frontend(struct dvb_frontend *fe);
+
static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open)
{
struct videobuf_dvb_frontends *f;
@@ -125,6 +129,12 @@ static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open)
if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
+
+ /*
+ * FIXME: Improve this path to avoid calling the
+ * cx23885_dvb_set_frontend() every time it passes here.
+ */
+ cx23885_dvb_set_frontend(fe->dvb.frontend);
}
static struct videobuf_queue_ops dvb_qops = {
@@ -479,15 +489,15 @@ static struct xc5000_config mygica_x8506_xc5000_config = {
.if_khz = 5380,
};
-static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *param)
+static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct cx23885_tsport *port = fe->dvb->priv;
struct cx23885_dev *dev = port->dev;
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1275:
- switch (param->u.vsb.modulation) {
+ switch (p->modulation) {
case VSB_8:
cx23885_gpio_clear(dev, GPIO_5);
break;
@@ -507,31 +517,6 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
return 0;
}
-static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe,
- unsigned int cmd, void *parg,
- unsigned int stage)
-{
- int err = 0;
-
- switch (stage) {
- case DVB_FE_IOCTL_PRE:
-
- switch (cmd) {
- case FE_SET_FRONTEND:
- err = cx23885_dvb_set_frontend(fe,
- (struct dvb_frontend_parameters *) parg);
- break;
- }
- break;
-
- case DVB_FE_IOCTL_POST:
- /* no post-ioctl handling required */
- break;
- }
- return err;
-};
-
-
static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
.prod = LGS8GXX_PROD_LGS8G75,
.demod_address = 0x19,
@@ -617,6 +602,24 @@ static struct xc5000_config netup_xc5000_config[] = {
},
};
+static struct drxk_config terratec_drxk_config[] = {
+ {
+ .adr = 0x29,
+ .no_i2c_bridge = 1,
+ }, {
+ .adr = 0x2a,
+ .no_i2c_bridge = 1,
+ },
+};
+
+static struct mt2063_config terratec_mt2063_config[] = {
+ {
+ .tuner_address = 0x60,
+ }, {
+ .tuner_address = 0x67,
+ },
+};
+
int netup_altera_fpga_rw(void *device, int flag, int data, int read)
{
struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -940,6 +943,11 @@ static int dvb_register(struct cx23885_tsport *port)
fe = dvb_attach(xc4000_attach, fe0->dvb.frontend,
&dev->i2c_bus[1].i2c_adap, &cfg);
+ if (!fe) {
+ printk(KERN_ERR "%s/2: xc4000 attach failed\n",
+ dev->name);
+ goto frontend_detach;
+ }
}
break;
case CX23885_BOARD_TBS_6920:
@@ -1043,6 +1051,20 @@ static int dvb_register(struct cx23885_tsport *port)
}
break;
case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+ &hcw_s5h1411_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[0].i2c_adap,
+ &hauppauge_tda18271_config);
+
+ tda18271_attach(&dev->ts1.analog_fe,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_tda18271_config);
+
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1290:
i2c_bus = &dev->i2c_bus[0];
fe0->dvb.frontend = dvb_attach(s5h1411_attach,
@@ -1118,6 +1140,39 @@ static int dvb_register(struct cx23885_tsport *port)
goto frontend_detach;
}
break;
+ case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+ i2c_bus = &dev->i2c_bus[0];
+ i2c_bus2 = &dev->i2c_bus[1];
+
+ switch (port->nr) {
+ /* port b */
+ case 1:
+ fe0->dvb.frontend = dvb_attach(drxk_attach,
+ &terratec_drxk_config[0],
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(mt2063_attach,
+ fe0->dvb.frontend,
+ &terratec_mt2063_config[0],
+ &i2c_bus2->i2c_adap))
+ goto frontend_detach;
+ }
+ break;
+ /* port c */
+ case 2:
+ fe0->dvb.frontend = dvb_attach(drxk_attach,
+ &terratec_drxk_config[1],
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(mt2063_attach,
+ fe0->dvb.frontend,
+ &terratec_mt2063_config[1],
+ &i2c_bus2->i2c_adap))
+ goto frontend_detach;
+ }
+ break;
+ }
+ break;
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
@@ -1151,7 +1206,7 @@ static int dvb_register(struct cx23885_tsport *port)
/* register everything */
ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
&dev->pci->dev, adapter_nr, mfe_shared,
- cx23885_dvb_fe_ioctl_override);
+ NULL);
if (ret)
goto frontend_detach;
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index 0ff7a9e98f3e..be1e21d8295c 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -309,7 +309,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
}
}
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
int cx23885_i2c_register(struct cx23885_i2c *bus)
{
struct cx23885_dev *dev = bus->dev;
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index e730b9263016..c654bdc7ccb2 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -253,9 +253,9 @@ static struct cx23885_ctrl cx23885_ctls[] = {
.id = V4L2_CID_AUDIO_VOLUME,
.name = "Volume",
.minimum = 0,
- .maximum = 0x3f,
- .step = 1,
- .default_value = 0x3f,
+ .maximum = 65535,
+ .step = 65535 / 100,
+ .default_value = 65535,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.reg = PATH1_VOL_CTL,
@@ -316,7 +316,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
__func__, bc);
}
-static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
+int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
{
dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
__func__,
@@ -344,8 +344,8 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
- snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
- dev->name, type, cx23885_boards[dev->board].name);
+ snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
+ cx23885_boards[dev->board].name, type);
video_set_drvdata(vfd, dev);
return vfd;
}
@@ -492,7 +492,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
dev->input = input;
if (dev->board == CX23885_BOARD_MYGICA_X8506 ||
- dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2) {
+ dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2 ||
+ dev->board == CX23885_BOARD_MYGICA_X8507) {
/* Select Analog TV */
if (INPUT(input)->type == CX23885_VMUX_TELEVISION)
cx23885_gpio_clear(dev, GPIO_0);
@@ -503,7 +504,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
INPUT(input)->vmux, 0, 0);
if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) ||
- (dev->board == CX23885_BOARD_MPX885)) {
+ (dev->board == CX23885_BOARD_MPX885) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) {
/* Configure audio routing */
v4l2_subdev_call(dev->sd_cx25840, audio, s_routing,
INPUT(input)->amux, 0, 0);
@@ -649,6 +651,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
int rc, init_buffer = 0;
u32 line0_offset, line1_offset;
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+ int field_tff;
BUG_ON(NULL == fh->fmt);
if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) ||
@@ -690,15 +693,25 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
buf->bpl, 0, buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
- if (dev->tvnorm & V4L2_STD_NTSC) {
+ if (dev->tvnorm & V4L2_STD_NTSC)
+ /* NTSC or */
+ field_tff = 1;
+ else
+ field_tff = 0;
+
+ if (cx23885_boards[dev->board].force_bff)
+ /* PAL / SECAM OR 888 in NTSC MODE */
+ field_tff = 0;
+
+ if (field_tff) {
/* cx25840 transmits NTSC bottom field first */
- dprintk(1, "%s() Creating NTSC risc\n",
+ dprintk(1, "%s() Creating TFF/NTSC risc\n",
__func__);
line0_offset = buf->bpl;
line1_offset = 0;
} else {
/* All other formats are top field first */
- dprintk(1, "%s() Creating PAL/SECAM risc\n",
+ dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
__func__);
line0_offset = 0;
line1_offset = buf->bpl;
@@ -981,6 +994,8 @@ static int video_release(struct file *file)
}
videobuf_mmap_free(&fh->vidq);
+ videobuf_mmap_free(&fh->vbiq);
+
file->private_data = NULL;
kfree(fh);
@@ -1002,7 +1017,7 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma)
/* ------------------------------------------------------------------ */
/* VIDEO CTRL IOCTLS */
-static int cx23885_get_control(struct cx23885_dev *dev,
+int cx23885_get_control(struct cx23885_dev *dev,
struct v4l2_control *ctl)
{
dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
@@ -1010,7 +1025,7 @@ static int cx23885_get_control(struct cx23885_dev *dev,
return 0;
}
-static int cx23885_set_control(struct cx23885_dev *dev,
+int cx23885_set_control(struct cx23885_dev *dev,
struct v4l2_control *ctl)
{
dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__);
@@ -1229,6 +1244,16 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
return 0;
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ dprintk(1, "%s()\n", __func__);
+
+ call_all(dev, core, g_std, id);
+
+ return 0;
+}
+
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
@@ -1241,7 +1266,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
return 0;
}
-static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
+int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
{
static const char *iname[] = {
[CX23885_VMUX_COMPOSITE1] = "Composite1",
@@ -1278,6 +1303,15 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
if (INPUT(n)->type != CX23885_VMUX_TELEVISION)
i->audioset = 0x3;
+ if (dev->input == n) {
+ /* enum'd input matches our configured input.
+ * Ask the video decoder to process the call
+ * and give it an oppertunity to update the
+ * status field.
+ */
+ call_all(dev, video, g_input_status, &i->status);
+ }
+
return 0;
}
@@ -1289,7 +1323,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
return cx23885_enum_input(dev, i);
}
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+int cx23885_get_input(struct file *file, void *priv, unsigned int *i)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
@@ -1298,7 +1332,12 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
return 0;
}
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ return cx23885_get_input(file, priv, i);
+}
+
+int cx23885_set_input(struct file *file, void *priv, unsigned int i)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
@@ -1322,6 +1361,11 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ return cx23885_set_input(file, priv, i);
+}
+
static int vidioc_log_status(struct file *file, void *priv)
{
struct cx23885_fh *fh = priv;
@@ -1329,11 +1373,11 @@ static int vidioc_log_status(struct file *file, void *priv)
printk(KERN_INFO
"%s/0: ============ START LOG STATUS ============\n",
- dev->name);
+ dev->name);
call_all(dev, core, log_status);
printk(KERN_INFO
"%s/0: ============= END LOG STATUS =============\n",
- dev->name);
+ dev->name);
return 0;
}
@@ -1471,6 +1515,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
{
+ struct v4l2_control ctrl;
+
if (unlikely(UNSET == dev->tuner_type))
return -EINVAL;
if (unlikely(f->tuner != 0))
@@ -1479,29 +1525,103 @@ static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
mutex_lock(&dev->lock);
dev->freq = f->frequency;
+ /* I need to mute audio here */
+ ctrl.id = V4L2_CID_AUDIO_MUTE;
+ ctrl.value = 1;
+ cx23885_set_control(dev, &ctrl);
+
call_all(dev, tuner, s_frequency, f);
/* When changing channels it is required to reset TVAUDIO */
- msleep(10);
+ msleep(100);
+
+ /* I need to unmute audio here */
+ ctrl.value = 0;
+ cx23885_set_control(dev, &ctrl);
mutex_unlock(&dev->lock);
return 0;
}
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
+ struct v4l2_frequency *f)
+{
+ struct v4l2_control ctrl;
+ struct videobuf_dvb_frontend *vfe;
+ struct dvb_frontend *fe;
+
+ struct analog_parameters params = {
+ .mode = V4L2_TUNER_ANALOG_TV,
+ .audmode = V4L2_TUNER_MODE_STEREO,
+ .std = dev->tvnorm,
+ .frequency = f->frequency
+ };
+
+ mutex_lock(&dev->lock);
+ dev->freq = f->frequency;
+
+ /* I need to mute audio here */
+ ctrl.id = V4L2_CID_AUDIO_MUTE;
+ ctrl.value = 1;
+ cx23885_set_control(dev, &ctrl);
+
+ /* If HVR1850 */
+ dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__,
+ params.frequency, f->tuner, params.std);
+
+ vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1);
+ if (!vfe) {
+ mutex_unlock(&dev->lock);
+ return -EINVAL;
+ }
+
+ fe = vfe->dvb.frontend;
+
+ if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)
+ fe = &dev->ts1.analog_fe;
+
+ if (fe && fe->ops.tuner_ops.set_analog_params) {
+ call_all(dev, core, s_std, dev->tvnorm);
+ fe->ops.tuner_ops.set_analog_params(fe, &params);
+ }
+ else
+ printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
+
+ /* When changing channels it is required to reset TVAUDIO */
+ msleep(100);
+
+ /* I need to unmute audio here */
+ ctrl.value = 0;
+ cx23885_set_control(dev, &ctrl);
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+int cx23885_set_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
{
struct cx23885_fh *fh = priv;
struct cx23885_dev *dev = fh->dev;
+ int ret;
- if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
- return -EINVAL;
- if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
- return -EINVAL;
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ ret = cx23885_set_freq_via_ops(dev, f);
+ break;
+ default:
+ ret = cx23885_set_freq(dev, f);
+ }
- return
- cx23885_set_freq(dev, f);
+ return ret;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ return cx23885_set_frequency(file, priv, f);
}
/* ----------------------------------------------------------- */
@@ -1613,6 +1733,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_querystd = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index b49036fe3ffd..f020f0568df4 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -87,6 +87,8 @@
#define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30
#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31
#define CX23885_BOARD_MPX885 32
+#define CX23885_BOARD_MYGICA_X8507 33
+#define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
@@ -226,6 +228,8 @@ struct cx23885_board {
u32 clk_freq;
struct cx23885_input input[MAX_CX23885_INPUT];
int ci_type; /* for NetUP */
+ /* Force bottom field first during DMA (888 workaround) */
+ u32 force_bff;
};
struct cx23885_subid {
@@ -310,6 +314,9 @@ struct cx23885_tsport {
u32 num_frontends;
void (*gate_ctrl)(struct cx23885_tsport *port, int open);
void *port_priv;
+
+ /* Workaround for a temp dvb_frontend that the tuner can attached to */
+ struct dvb_frontend analog_fe;
};
struct cx23885_kernel_ir {
@@ -574,6 +581,13 @@ extern void cx23885_video_unregister(struct cx23885_dev *dev);
extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status);
extern void cx23885_video_wakeup(struct cx23885_dev *dev,
struct cx23885_dmaqueue *q, u32 count);
+int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i);
+int cx23885_set_input(struct file *file, void *priv, unsigned int i);
+int cx23885_get_input(struct file *file, void *priv, unsigned int *i);
+int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f);
+int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
+int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
+int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
/* ----------------------------------------------------------- */
/* cx23885-vbi.c */
diff --git a/drivers/media/video/cx25821/cx25821-alsa.c b/drivers/media/video/cx25821/cx25821-alsa.c
index 09e99de5fd21..03cfac476b03 100644
--- a/drivers/media/video/cx25821/cx25821-alsa.c
+++ b/drivers/media/video/cx25821/cx25821-alsa.c
@@ -102,7 +102,7 @@ struct cx25821_audio_dev {
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 };
+static bool enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 };
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable cx25821 soundcard. default enabled.");
@@ -176,8 +176,7 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
/* Set the input mode to 16-bit */
tmp = cx_read(AUD_A_CFG);
- cx_write(AUD_A_CFG,
- tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE |
+ cx_write(AUD_A_CFG, tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE |
FLD_AUD_CLK_ENABLE);
/*
@@ -188,9 +187,8 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
*/
/* Enables corresponding bits at AUD_INT_STAT */
- cx_write(AUD_A_INT_MSK,
- FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF | FLD_AUD_DST_SYNC |
- FLD_AUD_DST_OPC_ERR);
+ cx_write(AUD_A_INT_MSK, FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF |
+ FLD_AUD_DST_SYNC | FLD_AUD_DST_OPC_ERR);
/* Clean any pending interrupt bits already set */
cx_write(AUD_A_INT_STAT, ~0);
@@ -200,8 +198,8 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
/* Turn on audio downstream fifo and risc enable 0x101 */
tmp = cx_read(AUD_INT_DMA_CTL);
- cx_set(AUD_INT_DMA_CTL,
- tmp | (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN));
+ cx_set(AUD_INT_DMA_CTL, tmp |
+ (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN));
mdelay(100);
return 0;
@@ -220,9 +218,8 @@ static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip)
/* disable irqs */
cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT);
- cx_clear(AUD_A_INT_MSK,
- AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | AUD_INT_DN_RISCI2 |
- AUD_INT_DN_RISCI1);
+ cx_clear(AUD_A_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+ AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
return 0;
}
@@ -234,15 +231,15 @@ static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip)
*/
static char *cx25821_aud_irqs[32] = {
"dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
- NULL, /* reserved */
+ NULL, /* reserved */
"dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */
- NULL, /* reserved */
- "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */
- NULL, /* reserved */
- "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */
- NULL, /* reserved */
- "opc_err", "par_err", "rip_err", /* 16-18 */
- "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */
+ NULL, /* reserved */
+ "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */
+ NULL, /* reserved */
+ "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */
+ NULL, /* reserved */
+ "opc_err", "par_err", "rip_err", /* 16-18 */
+ "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */
};
/*
@@ -258,10 +255,8 @@ static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status,
cx_write(AUD_A_INT_STAT, status);
if (debug > 1 || (status & mask & ~0xff))
- cx25821_print_irqbits(dev->name, "irq aud",
- cx25821_aud_irqs,
- ARRAY_SIZE(cx25821_aud_irqs), status,
- mask);
+ cx25821_print_irqbits(dev->name, "irq aud", cx25821_aud_irqs,
+ ARRAY_SIZE(cx25821_aud_irqs), status, mask);
/* risc op code error */
if (status & AUD_INT_OPC_ERR) {
@@ -270,8 +265,7 @@ static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status,
cx_clear(AUD_INT_DMA_CTL,
FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN);
cx25821_sram_channel_dump_audio(dev,
- &cx25821_sram_channels
- [AUDIO_SRAM_CHANNEL]);
+ &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]);
}
if (status & AUD_INT_DN_SYNC) {
pr_warn("WARNING %s: Downstream sync error!\n", dev->name);
@@ -317,8 +311,9 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id)
cx25821_aud_irq(chip, audint_status,
audint_mask);
break;
- } else
+ } else {
goto out;
+ }
}
handled = 1;
@@ -361,9 +356,8 @@ static int dsp_buffer_free(struct cx25821_audio_dev *chip)
*/
#define DEFAULT_FIFO_SIZE 384
static struct snd_pcm_hardware snd_cx25821_digital_hw = {
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID,
+ .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
@@ -396,8 +390,8 @@ static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream)
return -ENODEV;
}
- err =
- snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
+ err = snd_pcm_hw_constraint_pow2(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0)
goto _error;
@@ -468,8 +462,7 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
dma = &buf->dma;
videobuf_dma_init(dma);
ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
- (PAGE_ALIGN(chip->dma_size) >>
- PAGE_SHIFT));
+ (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
if (ret < 0)
goto error;
@@ -477,10 +470,8 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
goto error;
- ret =
- cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist,
- chip->period_size, chip->num_periods,
- 1);
+ ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist,
+ chip->period_size, chip->num_periods, 1);
if (ret < 0) {
pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
goto error;
@@ -686,7 +677,7 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
}
err = snd_card_create(index[devno], id[devno], THIS_MODULE,
- sizeof(struct cx25821_audio_dev), &card);
+ sizeof(struct cx25821_audio_dev), &card);
if (err < 0) {
pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n",
__func__);
@@ -711,8 +702,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
IRQF_SHARED, chip->dev->name, chip);
if (err < 0) {
- pr_err("ERROR %s: can't get IRQ %d for ALSA\n",
- chip->dev->name, dev->pci->irq);
+ pr_err("ERROR %s: can't get IRQ %d for ALSA\n", chip->dev->name,
+ dev->pci->irq);
goto error;
}
@@ -730,8 +721,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
chip->iobase, chip->irq);
strcpy(card->mixername, "CX25821");
- pr_info("%s/%i: ALSA support for cx25821 boards\n",
- card->driver, devno);
+ pr_info("%s/%i: ALSA support for cx25821 boards\n", card->driver,
+ devno);
err = snd_card_register(card);
if (err < 0) {
diff --git a/drivers/media/video/cx25821/cx25821-audio-upstream.c b/drivers/media/video/cx25821/cx25821-audio-upstream.c
index c20d6dece154..20c7ca3351a8 100644
--- a/drivers/media/video/cx25821/cx25821-audio-upstream.c
+++ b/drivers/media/video/cx25821/cx25821-audio-upstream.c
@@ -107,7 +107,7 @@ static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev,
{
unsigned int line;
struct sram_channel *sram_ch =
- dev->channels[dev->_audio_upstream_channel].sram_channels;
+ dev->channels[dev->_audio_upstream_channel].sram_channels;
int offset = 0;
/* scan lines */
@@ -175,10 +175,8 @@ int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev,
}
rp = cx25821_risc_field_upstream_audio(dev, rp,
- dev->
- _audiodata_buf_phys_addr
- + databuf_offset, bpl,
- fifo_enable);
+ dev->_audiodata_buf_phys_addr + databuf_offset,
+ bpl, fifo_enable);
if (USE_RISC_NOOP_AUDIO) {
for (i = 0; i < NUM_NO_OPS; i++)
@@ -193,7 +191,7 @@ int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev,
/* Recalculate virtual address based on frame index */
rp = dev->_risc_virt_addr + RISC_SYNC_INSTRUCTION_SIZE / 4 +
- (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4);
+ (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4);
}
return 0;
@@ -218,7 +216,7 @@ void cx25821_free_memory_audio(struct cx25821_dev *dev)
void cx25821_stop_upstream_audio(struct cx25821_dev *dev)
{
struct sram_channel *sram_ch =
- dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels;
+ dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels;
u32 tmp = 0;
if (!dev->_audio_is_running) {
@@ -286,14 +284,14 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
} else {
if (!(myfile->f_op)) {
pr_err("%s(): File has no file operations registered!\n",
- __func__);
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
pr_err("%s(): File has no READ operations registered!\n",
- __func__);
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
@@ -305,14 +303,14 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
for (i = 0; i < dev->_audio_lines_count; i++) {
pos = file_offset;
- vfs_read_retval =
- vfs_read(myfile, mybuf, line_size, &pos);
+ vfs_read_retval = vfs_read(myfile, mybuf, line_size,
+ &pos);
if (vfs_read_retval > 0 && vfs_read_retval == line_size
&& dev->_audiodata_buf_virt_addr != NULL) {
memcpy((void *)(dev->_audiodata_buf_virt_addr +
frame_offset / 4), mybuf,
- vfs_read_retval);
+ vfs_read_retval);
}
file_offset += vfs_read_retval;
@@ -328,8 +326,8 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
if (i > 0)
dev->_audioframe_count++;
- dev->_audiofile_status =
- (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+ dev->_audiofile_status = (vfs_read_retval == line_size) ?
+ IN_PROGRESS : END_OF_FILE;
set_fs(old_fs);
filp_close(myfile, NULL);
@@ -340,12 +338,12 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
static void cx25821_audioups_handler(struct work_struct *work)
{
- struct cx25821_dev *dev =
- container_of(work, struct cx25821_dev, _audio_work_entry);
+ struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
+ _audio_work_entry);
if (!dev) {
pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
- __func__);
+ __func__);
return;
}
@@ -370,19 +368,19 @@ int cx25821_openfile_audio(struct cx25821_dev *dev,
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
- __func__, dev->_audiofilename, open_errno);
+ __func__, dev->_audiofilename, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
pr_err("%s(): File has no file operations registered!\n",
- __func__);
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
pr_err("%s(): File has no READ operations registered!\n",
- __func__);
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
@@ -395,12 +393,12 @@ int cx25821_openfile_audio(struct cx25821_dev *dev,
for (i = 0; i < dev->_audio_lines_count; i++) {
pos = offset;
- vfs_read_retval =
- vfs_read(myfile, mybuf, line_size, &pos);
+ vfs_read_retval = vfs_read(myfile, mybuf,
+ line_size, &pos);
- if (vfs_read_retval > 0
- && vfs_read_retval == line_size
- && dev->_audiodata_buf_virt_addr != NULL) {
+ if (vfs_read_retval > 0 &&
+ vfs_read_retval == line_size &&
+ dev->_audiodata_buf_virt_addr != NULL) {
memcpy((void *)(dev->
_audiodata_buf_virt_addr
+ offset / 4), mybuf,
@@ -423,8 +421,8 @@ int cx25821_openfile_audio(struct cx25821_dev *dev,
break;
}
- dev->_audiofile_status =
- (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+ dev->_audiofile_status = (vfs_read_retval == line_size) ?
+ IN_PROGRESS : END_OF_FILE;
set_fs(old_fs);
myfile->f_pos = 0;
@@ -444,9 +442,8 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
cx25821_free_memory_audio(dev);
- dev->_risc_virt_addr =
- pci_alloc_consistent(dev->pci, dev->audio_upstream_riscbuf_size,
- &dma_addr);
+ dev->_risc_virt_addr = pci_alloc_consistent(dev->pci,
+ dev->audio_upstream_riscbuf_size, &dma_addr);
dev->_risc_virt_start_addr = dev->_risc_virt_addr;
dev->_risc_phys_start_addr = dma_addr;
dev->_risc_phys_addr = dma_addr;
@@ -454,22 +451,21 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
if (!dev->_risc_virt_addr) {
printk(KERN_DEBUG
- pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n"));
+ pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n"));
return -ENOMEM;
}
/* Clear out memory at address */
memset(dev->_risc_virt_addr, 0, dev->_audiorisc_size);
/* For Audio Data buffer allocation */
- dev->_audiodata_buf_virt_addr =
- pci_alloc_consistent(dev->pci, dev->audio_upstream_databuf_size,
- &data_dma_addr);
+ dev->_audiodata_buf_virt_addr = pci_alloc_consistent(dev->pci,
+ dev->audio_upstream_databuf_size, &data_dma_addr);
dev->_audiodata_buf_phys_addr = data_dma_addr;
dev->_audiodata_buf_size = dev->audio_upstream_databuf_size;
if (!dev->_audiodata_buf_virt_addr) {
printk(KERN_DEBUG
- pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n"));
+ pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n"));
return -ENOMEM;
}
/* Clear out memory at address */
@@ -480,12 +476,11 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
return ret;
/* Creating RISC programs */
- ret =
- cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl,
- dev->_audio_lines_count);
+ ret = cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl,
+ dev->_audio_lines_count);
if (ret < 0) {
printk(KERN_DEBUG
- pr_fmt("ERROR creating audio upstream RISC programs!\n"));
+ pr_fmt("ERROR creating audio upstream RISC programs!\n"));
goto error;
}
@@ -533,9 +528,9 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
if (dev->_risc_virt_start_addr != NULL) {
risc_phys_jump_addr =
- dev->_risc_phys_start_addr +
- RISC_SYNC_INSTRUCTION_SIZE +
- AUDIO_RISC_DMA_BUF_SIZE;
+ dev->_risc_phys_start_addr +
+ RISC_SYNC_INSTRUCTION_SIZE +
+ AUDIO_RISC_DMA_BUF_SIZE;
rp = cx25821_risc_field_upstream_audio(dev,
dev->_risc_virt_start_addr + 1,
@@ -632,7 +627,7 @@ static void cx25821_wait_fifo_enable(struct cx25821_dev *dev,
/* 10 millisecond timeout */
if (count++ > 1000) {
pr_err("ERROR: %s() fifo is NOT turned on. Timeout!\n",
- __func__);
+ __func__);
return;
}
@@ -661,9 +656,9 @@ int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev,
/* Set the input mode to 16-bit */
tmp = cx_read(sram_ch->aud_cfg);
- tmp |=
- FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE |
- FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D | FLD_AUD_SONY_MODE;
+ tmp |= FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE |
+ FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D |
+ FLD_AUD_SONY_MODE;
cx_write(sram_ch->aud_cfg, tmp);
/* Read and write back the interrupt status register to clear it */
@@ -678,12 +673,11 @@ int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev,
tmp = cx_read(sram_ch->int_msk);
cx_write(sram_ch->int_msk, tmp |= _intr_msk);
- err =
- request_irq(dev->pci->irq, cx25821_upstream_irq_audio,
+ err = request_irq(dev->pci->irq, cx25821_upstream_irq_audio,
IRQF_SHARED, dev->name, dev);
if (err < 0) {
- pr_err("%s: can't get upstream IRQ %d\n",
- dev->name, dev->pci->irq);
+ pr_err("%s: can't get upstream IRQ %d\n", dev->name,
+ dev->pci->irq);
goto fail_irq;
}
@@ -726,7 +720,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
if (!dev->_irq_audio_queues) {
printk(KERN_DEBUG
- pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n"));
+ pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n"));
return -ENOMEM;
}
@@ -739,33 +733,30 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
if (dev->input_audiofilename) {
str_length = strlen(dev->input_audiofilename);
- dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL);
+ dev->_audiofilename = kmemdup(dev->input_audiofilename,
+ str_length + 1, GFP_KERNEL);
if (!dev->_audiofilename)
goto error;
- memcpy(dev->_audiofilename, dev->input_audiofilename,
- str_length + 1);
-
/* Default if filename is empty string */
if (strcmp(dev->input_audiofilename, "") == 0)
dev->_audiofilename = "/root/audioGOOD.wav";
} else {
str_length = strlen(_defaultAudioName);
- dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL);
+ dev->_audiofilename = kmemdup(_defaultAudioName,
+ str_length + 1, GFP_KERNEL);
if (!dev->_audiofilename)
goto error;
-
- memcpy(dev->_audiofilename, _defaultAudioName, str_length + 1);
}
retval = cx25821_sram_channel_setup_upstream_audio(dev, sram_ch,
_line_size, 0);
dev->audio_upstream_riscbuf_size =
- AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS +
- RISC_SYNC_INSTRUCTION_SIZE;
+ AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS +
+ RISC_SYNC_INSTRUCTION_SIZE;
dev->audio_upstream_databuf_size = AUDIO_DATA_BUF_SZ * NUM_AUDIO_PROGS;
/* Allocating buffers and prepare RISC program */
@@ -773,7 +764,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
_line_size);
if (retval < 0) {
pr_err("%s: Failed to set up Audio upstream buffers!\n",
- dev->name);
+ dev->name);
goto error;
}
/* Start RISC engine */
diff --git a/drivers/media/video/cx25821/cx25821-audio.h b/drivers/media/video/cx25821/cx25821-audio.h
index 8eb55b7b88cb..1fc2d24f5110 100644
--- a/drivers/media/video/cx25821/cx25821-audio.h
+++ b/drivers/media/video/cx25821/cx25821-audio.h
@@ -23,39 +23,40 @@
#ifndef __CX25821_AUDIO_H__
#define __CX25821_AUDIO_H__
-#define USE_RISC_NOOP 1
-#define LINES_PER_BUFFER 15
-#define AUDIO_LINE_SIZE 128
+#define USE_RISC_NOOP 1
+#define LINES_PER_BUFFER 15
+#define AUDIO_LINE_SIZE 128
/* Number of buffer programs to use at once. */
-#define NUMBER_OF_PROGRAMS 8
+#define NUMBER_OF_PROGRAMS 8
/*
* Max size of the RISC program for a buffer. - worst case is 2 writes per line
* Space is also added for the 4 no-op instructions added on the end.
*/
#ifndef USE_RISC_NOOP
-#define MAX_BUFFER_PROGRAM_SIZE \
- (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE * 4)
+#define MAX_BUFFER_PROGRAM_SIZE \
+ (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \
+ RISC_WRITECR_INSTRUCTION_SIZE * 4)
#endif
/* MAE 12 July 2005 Try to use NOOP RISC instruction instead */
#ifdef USE_RISC_NOOP
-#define MAX_BUFFER_PROGRAM_SIZE \
- (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \
- RISC_NOOP_INSTRUCTION_SIZE * 4)
+#define MAX_BUFFER_PROGRAM_SIZE \
+ (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \
+ RISC_NOOP_INSTRUCTION_SIZE * 4)
#endif
/* Sizes of various instructions in bytes. Used when adding instructions. */
-#define RISC_WRITE_INSTRUCTION_SIZE 12
-#define RISC_JUMP_INSTRUCTION_SIZE 12
-#define RISC_SKIP_INSTRUCTION_SIZE 4
-#define RISC_SYNC_INSTRUCTION_SIZE 4
-#define RISC_WRITECR_INSTRUCTION_SIZE 16
-#define RISC_NOOP_INSTRUCTION_SIZE 4
-
-#define MAX_AUDIO_DMA_BUFFER_SIZE \
-(MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS + RISC_SYNC_INSTRUCTION_SIZE)
+#define RISC_WRITE_INSTRUCTION_SIZE 12
+#define RISC_JUMP_INSTRUCTION_SIZE 12
+#define RISC_SKIP_INSTRUCTION_SIZE 4
+#define RISC_SYNC_INSTRUCTION_SIZE 4
+#define RISC_WRITECR_INSTRUCTION_SIZE 16
+#define RISC_NOOP_INSTRUCTION_SIZE 4
+
+#define MAX_AUDIO_DMA_BUFFER_SIZE \
+ (MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS + \
+ RISC_SYNC_INSTRUCTION_SIZE)
#endif
diff --git a/drivers/media/video/cx25821/cx25821-cards.c b/drivers/media/video/cx25821/cx25821-cards.c
index 6ace60313b49..99988c988095 100644
--- a/drivers/media/video/cx25821/cx25821-cards.c
+++ b/drivers/media/video/cx25821/cx25821-cards.c
@@ -67,6 +67,6 @@ void cx25821_card_setup(struct cx25821_dev *dev)
if (dev->i2c_bus[0].i2c_rc == 0) {
dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
- sizeof(eeprom));
+ sizeof(eeprom));
}
}
diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c
index a7fa38f9594e..7930ca58349f 100644
--- a/drivers/media/video/cx25821/cx25821-core.c
+++ b/drivers/media/video/cx25821/cx25821-core.c
@@ -804,8 +804,8 @@ void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
u32 format)
{
if (channel_select <= 7 && channel_select >= 0) {
- cx_write(dev->channels[channel_select].
- sram_channels->pix_frmt, format);
+ cx_write(dev->channels[channel_select].sram_channels->pix_frmt,
+ format);
dev->channels[channel_select].pixel_formats = format;
}
}
@@ -855,21 +855,19 @@ static void cx25821_initialize(struct cx25821_dev *dev)
}
cx25821_sram_channel_setup_audio(dev,
- dev->channels[SRAM_CH08].sram_channels,
- 128, 0);
+ dev->channels[SRAM_CH08].sram_channels, 128, 0);
cx25821_gpio_init(dev);
}
static int cx25821_get_resources(struct cx25821_dev *dev)
{
- if (request_mem_region
- (pci_resource_start(dev->pci, 0), pci_resource_len(dev->pci, 0),
- dev->name))
+ if (request_mem_region(pci_resource_start(dev->pci, 0),
+ pci_resource_len(dev->pci, 0), dev->name))
return 0;
pr_err("%s: can't get MMIO memory @ 0x%llx\n",
- dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
+ dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
return -EBUSY;
}
@@ -972,8 +970,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
dev->lmmio = ioremap(dev->base_io_addr, pci_resource_len(dev->pci, 0));
if (!dev->lmmio) {
- CX25821_ERR
- ("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n");
+ CX25821_ERR("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n");
cx25821_iounmap(dev);
return -ENOMEM;
}
@@ -994,7 +991,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
* cx25821_i2c_register(&dev->i2c_bus[2]); */
CX25821_INFO("i2c register! bus->i2c_rc = %d\n",
- dev->i2c_bus[0].i2c_rc);
+ dev->i2c_bus[0].i2c_rc);
cx25821_card_setup(dev);
@@ -1004,9 +1001,8 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
cx25821_video_register(dev);
/* register IOCTL device */
- dev->ioctl_dev =
- cx25821_vdev_init(dev, dev->pci, &cx25821_videoioctl_template,
- "video");
+ dev->ioctl_dev = cx25821_vdev_init(dev, dev->pci,
+ &cx25821_videoioctl_template, "video");
if (video_register_device
(dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) {
@@ -1103,16 +1099,15 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
}
if (bpl <= sg_dma_len(sg) - offset) {
/* fits into current chunk */
- *(rp++) =
- cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | bpl);
+ *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL |
+ bpl);
*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
offset += bpl;
} else {
/* scanline needs to be split */
todo = bpl;
- *(rp++) =
- cpu_to_le32(RISC_WRITE | RISC_SOL |
+ *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL |
(sg_dma_len(sg) - offset));
*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
@@ -1120,8 +1115,8 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
offset = 0;
sg++;
while (todo > sg_dma_len(sg)) {
- *(rp++) =
- cpu_to_le32(RISC_WRITE | sg_dma_len(sg));
+ *(rp++) = cpu_to_le32(RISC_WRITE |
+ sg_dma_len(sg));
*(rp++) = cpu_to_le32(sg_dma_address(sg));
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= sg_dma_len(sg);
@@ -1160,8 +1155,8 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
can cause next bpl to start close to a page border. First DMA
region may be smaller than PAGE_SIZE */
/* write and jump need and extra dword */
- instructions =
- fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
+ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE +
+ lines);
instructions += 2;
rc = btcx_riscmem_alloc(pci, risc, instructions * 12);
@@ -1215,8 +1210,8 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
if (bpl <= sg_dma_len(sg) - offset) {
/* fits into current chunk */
- *(rp++) =
- cpu_to_le32(RISC_WRITE | sol | RISC_EOL | bpl);
+ *(rp++) = cpu_to_le32(RISC_WRITE | sol | RISC_EOL |
+ bpl);
*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
offset += bpl;
@@ -1224,7 +1219,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
/* scanline needs to be split */
todo = bpl;
*(rp++) = cpu_to_le32(RISC_WRITE | sol |
- (sg_dma_len(sg) - offset));
+ (sg_dma_len(sg) - offset));
*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= (sg_dma_len(sg) - offset);
@@ -1232,7 +1227,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
sg++;
while (todo > sg_dma_len(sg)) {
*(rp++) = cpu_to_le32(RISC_WRITE |
- sg_dma_len(sg));
+ sg_dma_len(sg));
*(rp++) = cpu_to_le32(sg_dma_address(sg));
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= sg_dma_len(sg);
@@ -1339,8 +1334,8 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id)
sram_channels->int_stat);
if (vid_status)
- handled +=
- cx25821_video_irq(dev, i, vid_status);
+ handled += cx25821_video_irq(dev, i,
+ vid_status);
cx_write(PCI_INT_STAT, mask[i]);
}
@@ -1427,9 +1422,8 @@ static int __devinit cx25821_initdev(struct pci_dev *pci_dev,
goto fail_irq;
}
- err =
- request_irq(pci_dev->irq, cx25821_irq, IRQF_SHARED,
- dev->name, dev);
+ err = request_irq(pci_dev->irq, cx25821_irq,
+ IRQF_SHARED, dev->name, dev);
if (err < 0) {
pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq);
@@ -1480,8 +1474,13 @@ static DEFINE_PCI_DEVICE_TABLE(cx25821_pci_tbl) = {
.device = 0x8210,
.subvendor = 0x14f1,
.subdevice = 0x0920,
- },
- {
+ }, {
+ /* CX25821 No Brand */
+ .vendor = 0x14f1,
+ .device = 0x8210,
+ .subvendor = 0x0000,
+ .subdevice = 0x0000,
+ }, {
/* --- end of list --- */
}
};
@@ -1512,6 +1511,5 @@ static void __exit cx25821_fini(void)
pci_unregister_driver(&cx25821_pci_driver);
}
-
module_init(cx25821_init);
module_exit(cx25821_fini);
diff --git a/drivers/media/video/cx25821/cx25821-i2c.c b/drivers/media/video/cx25821/cx25821-i2c.c
index 4d3d0ce40785..12d7300fa1e9 100644
--- a/drivers/media/video/cx25821/cx25821-i2c.c
+++ b/drivers/media/video/cx25821/cx25821-i2c.c
@@ -252,8 +252,8 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
msgs[i].addr == msgs[i + 1].addr) {
/* write then read from same address */
- retval =
- i2c_sendbytes(i2c_adap, &msgs[i], msgs[i + 1].len);
+ retval = i2c_sendbytes(i2c_adap, &msgs[i],
+ msgs[i + 1].len);
if (retval < 0)
goto err;
@@ -276,10 +276,8 @@ err:
static u32 cx25821_functionality(struct i2c_adapter *adap)
{
- return I2C_FUNC_SMBUS_EMUL |
- I2C_FUNC_I2C |
- I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
}
static struct i2c_algorithm cx25821_i2c_algo_template = {
@@ -300,7 +298,7 @@ static struct i2c_client cx25821_i2c_client_template = {
.name = "cx25821 internal",
};
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
int cx25821_i2c_register(struct cx25821_i2c *bus)
{
struct cx25821_dev *dev = bus->dev;
diff --git a/drivers/media/video/cx25821/cx25821-medusa-defines.h b/drivers/media/video/cx25821/cx25821-medusa-defines.h
index 60d197f57556..7a9e6470ba22 100644
--- a/drivers/media/video/cx25821/cx25821-medusa-defines.h
+++ b/drivers/media/video/cx25821/cx25821-medusa-defines.h
@@ -23,7 +23,7 @@
#ifndef _MEDUSA_DEF_H_
#define _MEDUSA_DEF_H_
-/* Video deocder that we supported */
+/* Video decoder that we supported */
#define VDEC_A 0
#define VDEC_B 1
#define VDEC_C 2
@@ -34,9 +34,9 @@
#define VDEC_H 7
/* end of display sequence */
-#define END_OF_SEQ 0xF;
+#define END_OF_SEQ 0xF;
/* registry string size */
-#define MAX_REGISTRY_SZ 40;
+#define MAX_REGISTRY_SZ 40;
#endif
diff --git a/drivers/media/video/cx25821/cx25821-medusa-reg.h b/drivers/media/video/cx25821/cx25821-medusa-reg.h
index 1c1c228352d1..c98ac946b277 100644
--- a/drivers/media/video/cx25821/cx25821-medusa-reg.h
+++ b/drivers/media/video/cx25821/cx25821-medusa-reg.h
@@ -28,22 +28,22 @@
#define HOST_REGISTER2 0x0001
/* Chip Configuration Registers */
-#define CHIP_CTRL 0x0100
-#define AFE_AB_CTRL 0x0104
-#define AFE_CD_CTRL 0x0108
-#define AFE_EF_CTRL 0x010C
-#define AFE_GH_CTRL 0x0110
+#define CHIP_CTRL 0x0100
+#define AFE_AB_CTRL 0x0104
+#define AFE_CD_CTRL 0x0108
+#define AFE_EF_CTRL 0x010C
+#define AFE_GH_CTRL 0x0110
#define DENC_AB_CTRL 0x0114
-#define BYP_AB_CTRL 0x0118
-#define MON_A_CTRL 0x011C
-#define DISP_SEQ_A 0x0120
-#define DISP_SEQ_B 0x0124
-#define DISP_AB_CNT 0x0128
-#define DISP_CD_CNT 0x012C
-#define DISP_EF_CNT 0x0130
-#define DISP_GH_CNT 0x0134
-#define DISP_IJ_CNT 0x0138
-#define PIN_OE_CTRL 0x013C
+#define BYP_AB_CTRL 0x0118
+#define MON_A_CTRL 0x011C
+#define DISP_SEQ_A 0x0120
+#define DISP_SEQ_B 0x0124
+#define DISP_AB_CNT 0x0128
+#define DISP_CD_CNT 0x012C
+#define DISP_EF_CNT 0x0130
+#define DISP_GH_CNT 0x0134
+#define DISP_IJ_CNT 0x0138
+#define PIN_OE_CTRL 0x013C
#define PIN_SPD_CTRL 0x0140
#define PIN_SPD_CTRL2 0x0144
#define IRQ_STAT_CTRL 0x0148
@@ -51,8 +51,8 @@
#define POWER_CTRL_CD 0x0150
#define POWER_CTRL_EF 0x0154
#define POWER_CTRL_GH 0x0158
-#define TUNE_CTRL 0x015C
-#define BIAS_CTRL 0x0160
+#define TUNE_CTRL 0x015C
+#define BIAS_CTRL 0x0160
#define AFE_AB_DIAG_CTRL 0x0164
#define AFE_CD_DIAG_CTRL 0x0168
#define AFE_EF_DIAG_CTRL 0x016C
@@ -61,17 +61,17 @@
#define PLL_CD_DIAG_CTRL 0x0178
#define PLL_EF_DIAG_CTRL 0x017C
#define PLL_GH_DIAG_CTRL 0x0180
-#define TEST_CTRL 0x0184
-#define BIST_STAT 0x0188
-#define BIST_STAT2 0x018C
-#define BIST_VID_PLL_AB_STAT 0x0190
-#define BIST_VID_PLL_CD_STAT 0x0194
-#define BIST_VID_PLL_EF_STAT 0x0198
-#define BIST_VID_PLL_GH_STAT 0x019C
+#define TEST_CTRL 0x0184
+#define BIST_STAT 0x0188
+#define BIST_STAT2 0x018C
+#define BIST_VID_PLL_AB_STAT 0x0190
+#define BIST_VID_PLL_CD_STAT 0x0194
+#define BIST_VID_PLL_EF_STAT 0x0198
+#define BIST_VID_PLL_GH_STAT 0x019C
#define DLL_DIAG_CTRL 0x01A0
#define DEV_CH_ID_CTRL 0x01A4
#define ABIST_CTRL_STATUS 0x01A8
-#define ABIST_FREQ 0x01AC
+#define ABIST_FREQ 0x01AC
#define ABIST_GOERT_SHIFT 0x01B0
#define ABIST_COEF12 0x01B4
#define ABIST_COEF34 0x01B8
@@ -92,357 +92,357 @@
#define ABIST_CLAMP_E 0x01F4
#define ABIST_CLAMP_F 0x01F8
-/* Digital Video Encoder A Registers */
-#define DENC_A_REG_1 0x0200
-#define DENC_A_REG_2 0x0204
-#define DENC_A_REG_3 0x0208
-#define DENC_A_REG_4 0x020C
-#define DENC_A_REG_5 0x0210
-#define DENC_A_REG_6 0x0214
-#define DENC_A_REG_7 0x0218
-#define DENC_A_REG_8 0x021C
+/* Digital Video Encoder A Registers */
+#define DENC_A_REG_1 0x0200
+#define DENC_A_REG_2 0x0204
+#define DENC_A_REG_3 0x0208
+#define DENC_A_REG_4 0x020C
+#define DENC_A_REG_5 0x0210
+#define DENC_A_REG_6 0x0214
+#define DENC_A_REG_7 0x0218
+#define DENC_A_REG_8 0x021C
-/* Digital Video Encoder B Registers */
-#define DENC_B_REG_1 0x0300
-#define DENC_B_REG_2 0x0304
-#define DENC_B_REG_3 0x0308
-#define DENC_B_REG_4 0x030C
-#define DENC_B_REG_5 0x0310
-#define DENC_B_REG_6 0x0314
-#define DENC_B_REG_7 0x0318
-#define DENC_B_REG_8 0x031C
+/* Digital Video Encoder B Registers */
+#define DENC_B_REG_1 0x0300
+#define DENC_B_REG_2 0x0304
+#define DENC_B_REG_3 0x0308
+#define DENC_B_REG_4 0x030C
+#define DENC_B_REG_5 0x0310
+#define DENC_B_REG_6 0x0314
+#define DENC_B_REG_7 0x0318
+#define DENC_B_REG_8 0x031C
-/* Video Decoder A Registers */
-#define MODE_CTRL 0x1000
-#define OUT_CTRL1 0x1004
-#define OUT_CTRL_NS 0x1008
-#define GEN_STAT 0x100C
-#define INT_STAT_MASK 0x1010
-#define LUMA_CTRL 0x1014
-#define CHROMA_CTRL 0x1018
-#define CRUSH_CTRL 0x101C
-#define HORIZ_TIM_CTRL 0x1020
-#define VERT_TIM_CTRL 0x1024
-#define MISC_TIM_CTRL 0x1028
-#define FIELD_COUNT 0x102C
-#define HSCALE_CTRL 0x1030
-#define VSCALE_CTRL 0x1034
-#define MAN_VGA_CTRL 0x1038
-#define MAN_AGC_CTRL 0x103C
-#define DFE_CTRL1 0x1040
-#define DFE_CTRL2 0x1044
-#define DFE_CTRL3 0x1048
-#define PLL_CTRL 0x104C
-#define PLL_CTRL_FAST 0x1050
-#define HTL_CTRL 0x1054
-#define SRC_CFG 0x1058
-#define SC_STEP_SIZE 0x105C
-#define SC_CONVERGE_CTRL 0x1060
-#define SC_LOOP_CTRL 0x1064
-#define COMB_2D_HFS_CFG 0x1068
-#define COMB_2D_HFD_CFG 0x106C
-#define COMB_2D_LF_CFG 0x1070
-#define COMB_2D_BLEND 0x1074
-#define COMB_MISC_CTRL 0x1078
+/* Video Decoder A Registers */
+#define MODE_CTRL 0x1000
+#define OUT_CTRL1 0x1004
+#define OUT_CTRL_NS 0x1008
+#define GEN_STAT 0x100C
+#define INT_STAT_MASK 0x1010
+#define LUMA_CTRL 0x1014
+#define CHROMA_CTRL 0x1018
+#define CRUSH_CTRL 0x101C
+#define HORIZ_TIM_CTRL 0x1020
+#define VERT_TIM_CTRL 0x1024
+#define MISC_TIM_CTRL 0x1028
+#define FIELD_COUNT 0x102C
+#define HSCALE_CTRL 0x1030
+#define VSCALE_CTRL 0x1034
+#define MAN_VGA_CTRL 0x1038
+#define MAN_AGC_CTRL 0x103C
+#define DFE_CTRL1 0x1040
+#define DFE_CTRL2 0x1044
+#define DFE_CTRL3 0x1048
+#define PLL_CTRL 0x104C
+#define PLL_CTRL_FAST 0x1050
+#define HTL_CTRL 0x1054
+#define SRC_CFG 0x1058
+#define SC_STEP_SIZE 0x105C
+#define SC_CONVERGE_CTRL 0x1060
+#define SC_LOOP_CTRL 0x1064
+#define COMB_2D_HFS_CFG 0x1068
+#define COMB_2D_HFD_CFG 0x106C
+#define COMB_2D_LF_CFG 0x1070
+#define COMB_2D_BLEND 0x1074
+#define COMB_MISC_CTRL 0x1078
#define COMB_FLAT_THRESH_CTRL 0x107C
-#define COMB_TEST 0x1080
-#define BP_MISC_CTRL 0x1084
-#define VCR_DET_CTRL 0x1088
-#define NOISE_DET_CTRL 0x108C
+#define COMB_TEST 0x1080
+#define BP_MISC_CTRL 0x1084
+#define VCR_DET_CTRL 0x1088
+#define NOISE_DET_CTRL 0x108C
#define COMB_FLAT_NOISE_CTRL 0x1090
-#define VERSION 0x11F8
-#define SOFT_RST_CTRL 0x11FC
+#define VERSION 0x11F8
+#define SOFT_RST_CTRL 0x11FC
-/* Video Decoder B Registers */
-#define VDEC_B_MODE_CTRL 0x1200
-#define VDEC_B_OUT_CTRL1 0x1204
-#define VDEC_B_OUT_CTRL_NS 0x1208
-#define VDEC_B_GEN_STAT 0x120C
+/* Video Decoder B Registers */
+#define VDEC_B_MODE_CTRL 0x1200
+#define VDEC_B_OUT_CTRL1 0x1204
+#define VDEC_B_OUT_CTRL_NS 0x1208
+#define VDEC_B_GEN_STAT 0x120C
#define VDEC_B_INT_STAT_MASK 0x1210
-#define VDEC_B_LUMA_CTRL 0x1214
-#define VDEC_B_CHROMA_CTRL 0x1218
-#define VDEC_B_CRUSH_CTRL 0x121C
+#define VDEC_B_LUMA_CTRL 0x1214
+#define VDEC_B_CHROMA_CTRL 0x1218
+#define VDEC_B_CRUSH_CTRL 0x121C
#define VDEC_B_HORIZ_TIM_CTRL 0x1220
#define VDEC_B_VERT_TIM_CTRL 0x1224
#define VDEC_B_MISC_TIM_CTRL 0x1228
-#define VDEC_B_FIELD_COUNT 0x122C
-#define VDEC_B_HSCALE_CTRL 0x1230
-#define VDEC_B_VSCALE_CTRL 0x1234
-#define VDEC_B_MAN_VGA_CTRL 0x1238
-#define VDEC_B_MAN_AGC_CTRL 0x123C
-#define VDEC_B_DFE_CTRL1 0x1240
-#define VDEC_B_DFE_CTRL2 0x1244
-#define VDEC_B_DFE_CTRL3 0x1248
-#define VDEC_B_PLL_CTRL 0x124C
+#define VDEC_B_FIELD_COUNT 0x122C
+#define VDEC_B_HSCALE_CTRL 0x1230
+#define VDEC_B_VSCALE_CTRL 0x1234
+#define VDEC_B_MAN_VGA_CTRL 0x1238
+#define VDEC_B_MAN_AGC_CTRL 0x123C
+#define VDEC_B_DFE_CTRL1 0x1240
+#define VDEC_B_DFE_CTRL2 0x1244
+#define VDEC_B_DFE_CTRL3 0x1248
+#define VDEC_B_PLL_CTRL 0x124C
#define VDEC_B_PLL_CTRL_FAST 0x1250
-#define VDEC_B_HTL_CTRL 0x1254
-#define VDEC_B_SRC_CFG 0x1258
-#define VDEC_B_SC_STEP_SIZE 0x125C
+#define VDEC_B_HTL_CTRL 0x1254
+#define VDEC_B_SRC_CFG 0x1258
+#define VDEC_B_SC_STEP_SIZE 0x125C
#define VDEC_B_SC_CONVERGE_CTRL 0x1260
-#define VDEC_B_SC_LOOP_CTRL 0x1264
+#define VDEC_B_SC_LOOP_CTRL 0x1264
#define VDEC_B_COMB_2D_HFS_CFG 0x1268
#define VDEC_B_COMB_2D_HFD_CFG 0x126C
#define VDEC_B_COMB_2D_LF_CFG 0x1270
#define VDEC_B_COMB_2D_BLEND 0x1274
#define VDEC_B_COMB_MISC_CTRL 0x1278
-#define VDEC_B_COMB_FLAT_THRESH_CTRL 0x127C
-#define VDEC_B_COMB_TEST 0x1280
-#define VDEC_B_BP_MISC_CTRL 0x1284
-#define VDEC_B_VCR_DET_CTRL 0x1288
+#define VDEC_B_COMB_FLAT_THRESH_CTRL 0x127C
+#define VDEC_B_COMB_TEST 0x1280
+#define VDEC_B_BP_MISC_CTRL 0x1284
+#define VDEC_B_VCR_DET_CTRL 0x1288
#define VDEC_B_NOISE_DET_CTRL 0x128C
#define VDEC_B_COMB_FLAT_NOISE_CTRL 0x1290
-#define VDEC_B_VERSION 0x13F8
+#define VDEC_B_VERSION 0x13F8
#define VDEC_B_SOFT_RST_CTRL 0x13FC
/* Video Decoder C Registers */
-#define VDEC_C_MODE_CTRL 0x1400
-#define VDEC_C_OUT_CTRL1 0x1404
-#define VDEC_C_OUT_CTRL_NS 0x1408
-#define VDEC_C_GEN_STAT 0x140C
+#define VDEC_C_MODE_CTRL 0x1400
+#define VDEC_C_OUT_CTRL1 0x1404
+#define VDEC_C_OUT_CTRL_NS 0x1408
+#define VDEC_C_GEN_STAT 0x140C
#define VDEC_C_INT_STAT_MASK 0x1410
-#define VDEC_C_LUMA_CTRL 0x1414
-#define VDEC_C_CHROMA_CTRL 0x1418
-#define VDEC_C_CRUSH_CTRL 0x141C
+#define VDEC_C_LUMA_CTRL 0x1414
+#define VDEC_C_CHROMA_CTRL 0x1418
+#define VDEC_C_CRUSH_CTRL 0x141C
#define VDEC_C_HORIZ_TIM_CTRL 0x1420
#define VDEC_C_VERT_TIM_CTRL 0x1424
#define VDEC_C_MISC_TIM_CTRL 0x1428
-#define VDEC_C_FIELD_COUNT 0x142C
-#define VDEC_C_HSCALE_CTRL 0x1430
-#define VDEC_C_VSCALE_CTRL 0x1434
-#define VDEC_C_MAN_VGA_CTRL 0x1438
-#define VDEC_C_MAN_AGC_CTRL 0x143C
-#define VDEC_C_DFE_CTRL1 0x1440
-#define VDEC_C_DFE_CTRL2 0x1444
-#define VDEC_C_DFE_CTRL3 0x1448
-#define VDEC_C_PLL_CTRL 0x144C
+#define VDEC_C_FIELD_COUNT 0x142C
+#define VDEC_C_HSCALE_CTRL 0x1430
+#define VDEC_C_VSCALE_CTRL 0x1434
+#define VDEC_C_MAN_VGA_CTRL 0x1438
+#define VDEC_C_MAN_AGC_CTRL 0x143C
+#define VDEC_C_DFE_CTRL1 0x1440
+#define VDEC_C_DFE_CTRL2 0x1444
+#define VDEC_C_DFE_CTRL3 0x1448
+#define VDEC_C_PLL_CTRL 0x144C
#define VDEC_C_PLL_CTRL_FAST 0x1450
-#define VDEC_C_HTL_CTRL 0x1454
-#define VDEC_C_SRC_CFG 0x1458
-#define VDEC_C_SC_STEP_SIZE 0x145C
+#define VDEC_C_HTL_CTRL 0x1454
+#define VDEC_C_SRC_CFG 0x1458
+#define VDEC_C_SC_STEP_SIZE 0x145C
#define VDEC_C_SC_CONVERGE_CTRL 0x1460
-#define VDEC_C_SC_LOOP_CTRL 0x1464
+#define VDEC_C_SC_LOOP_CTRL 0x1464
#define VDEC_C_COMB_2D_HFS_CFG 0x1468
#define VDEC_C_COMB_2D_HFD_CFG 0x146C
#define VDEC_C_COMB_2D_LF_CFG 0x1470
#define VDEC_C_COMB_2D_BLEND 0x1474
#define VDEC_C_COMB_MISC_CTRL 0x1478
-#define VDEC_C_COMB_FLAT_THRESH_CTRL 0x147C
-#define VDEC_C_COMB_TEST 0x1480
-#define VDEC_C_BP_MISC_CTRL 0x1484
-#define VDEC_C_VCR_DET_CTRL 0x1488
+#define VDEC_C_COMB_FLAT_THRESH_CTRL 0x147C
+#define VDEC_C_COMB_TEST 0x1480
+#define VDEC_C_BP_MISC_CTRL 0x1484
+#define VDEC_C_VCR_DET_CTRL 0x1488
#define VDEC_C_NOISE_DET_CTRL 0x148C
#define VDEC_C_COMB_FLAT_NOISE_CTRL 0x1490
-#define VDEC_C_VERSION 0x15F8
+#define VDEC_C_VERSION 0x15F8
#define VDEC_C_SOFT_RST_CTRL 0x15FC
/* Video Decoder D Registers */
-#define VDEC_D_MODE_CTRL 0x1600
-#define VDEC_D_OUT_CTRL1 0x1604
-#define VDEC_D_OUT_CTRL_NS 0x1608
-#define VDEC_D_GEN_STAT 0x160C
+#define VDEC_D_MODE_CTRL 0x1600
+#define VDEC_D_OUT_CTRL1 0x1604
+#define VDEC_D_OUT_CTRL_NS 0x1608
+#define VDEC_D_GEN_STAT 0x160C
#define VDEC_D_INT_STAT_MASK 0x1610
-#define VDEC_D_LUMA_CTRL 0x1614
-#define VDEC_D_CHROMA_CTRL 0x1618
-#define VDEC_D_CRUSH_CTRL 0x161C
+#define VDEC_D_LUMA_CTRL 0x1614
+#define VDEC_D_CHROMA_CTRL 0x1618
+#define VDEC_D_CRUSH_CTRL 0x161C
#define VDEC_D_HORIZ_TIM_CTRL 0x1620
#define VDEC_D_VERT_TIM_CTRL 0x1624
#define VDEC_D_MISC_TIM_CTRL 0x1628
-#define VDEC_D_FIELD_COUNT 0x162C
-#define VDEC_D_HSCALE_CTRL 0x1630
-#define VDEC_D_VSCALE_CTRL 0x1634
-#define VDEC_D_MAN_VGA_CTRL 0x1638
-#define VDEC_D_MAN_AGC_CTRL 0x163C
-#define VDEC_D_DFE_CTRL1 0x1640
-#define VDEC_D_DFE_CTRL2 0x1644
-#define VDEC_D_DFE_CTRL3 0x1648
-#define VDEC_D_PLL_CTRL 0x164C
+#define VDEC_D_FIELD_COUNT 0x162C
+#define VDEC_D_HSCALE_CTRL 0x1630
+#define VDEC_D_VSCALE_CTRL 0x1634
+#define VDEC_D_MAN_VGA_CTRL 0x1638
+#define VDEC_D_MAN_AGC_CTRL 0x163C
+#define VDEC_D_DFE_CTRL1 0x1640
+#define VDEC_D_DFE_CTRL2 0x1644
+#define VDEC_D_DFE_CTRL3 0x1648
+#define VDEC_D_PLL_CTRL 0x164C
#define VDEC_D_PLL_CTRL_FAST 0x1650
-#define VDEC_D_HTL_CTRL 0x1654
-#define VDEC_D_SRC_CFG 0x1658
-#define VDEC_D_SC_STEP_SIZE 0x165C
+#define VDEC_D_HTL_CTRL 0x1654
+#define VDEC_D_SRC_CFG 0x1658
+#define VDEC_D_SC_STEP_SIZE 0x165C
#define VDEC_D_SC_CONVERGE_CTRL 0x1660
-#define VDEC_D_SC_LOOP_CTRL 0x1664
+#define VDEC_D_SC_LOOP_CTRL 0x1664
#define VDEC_D_COMB_2D_HFS_CFG 0x1668
#define VDEC_D_COMB_2D_HFD_CFG 0x166C
#define VDEC_D_COMB_2D_LF_CFG 0x1670
#define VDEC_D_COMB_2D_BLEND 0x1674
#define VDEC_D_COMB_MISC_CTRL 0x1678
-#define VDEC_D_COMB_FLAT_THRESH_CTRL 0x167C
-#define VDEC_D_COMB_TEST 0x1680
-#define VDEC_D_BP_MISC_CTRL 0x1684
-#define VDEC_D_VCR_DET_CTRL 0x1688
+#define VDEC_D_COMB_FLAT_THRESH_CTRL 0x167C
+#define VDEC_D_COMB_TEST 0x1680
+#define VDEC_D_BP_MISC_CTRL 0x1684
+#define VDEC_D_VCR_DET_CTRL 0x1688
#define VDEC_D_NOISE_DET_CTRL 0x168C
#define VDEC_D_COMB_FLAT_NOISE_CTRL 0x1690
-#define VDEC_D_VERSION 0x17F8
+#define VDEC_D_VERSION 0x17F8
#define VDEC_D_SOFT_RST_CTRL 0x17FC
/* Video Decoder E Registers */
-#define VDEC_E_MODE_CTRL 0x1800
-#define VDEC_E_OUT_CTRL1 0x1804
-#define VDEC_E_OUT_CTRL_NS 0x1808
-#define VDEC_E_GEN_STAT 0x180C
+#define VDEC_E_MODE_CTRL 0x1800
+#define VDEC_E_OUT_CTRL1 0x1804
+#define VDEC_E_OUT_CTRL_NS 0x1808
+#define VDEC_E_GEN_STAT 0x180C
#define VDEC_E_INT_STAT_MASK 0x1810
-#define VDEC_E_LUMA_CTRL 0x1814
-#define VDEC_E_CHROMA_CTRL 0x1818
-#define VDEC_E_CRUSH_CTRL 0x181C
+#define VDEC_E_LUMA_CTRL 0x1814
+#define VDEC_E_CHROMA_CTRL 0x1818
+#define VDEC_E_CRUSH_CTRL 0x181C
#define VDEC_E_HORIZ_TIM_CTRL 0x1820
#define VDEC_E_VERT_TIM_CTRL 0x1824
#define VDEC_E_MISC_TIM_CTRL 0x1828
-#define VDEC_E_FIELD_COUNT 0x182C
-#define VDEC_E_HSCALE_CTRL 0x1830
-#define VDEC_E_VSCALE_CTRL 0x1834
-#define VDEC_E_MAN_VGA_CTRL 0x1838
-#define VDEC_E_MAN_AGC_CTRL 0x183C
-#define VDEC_E_DFE_CTRL1 0x1840
-#define VDEC_E_DFE_CTRL2 0x1844
-#define VDEC_E_DFE_CTRL3 0x1848
-#define VDEC_E_PLL_CTRL 0x184C
+#define VDEC_E_FIELD_COUNT 0x182C
+#define VDEC_E_HSCALE_CTRL 0x1830
+#define VDEC_E_VSCALE_CTRL 0x1834
+#define VDEC_E_MAN_VGA_CTRL 0x1838
+#define VDEC_E_MAN_AGC_CTRL 0x183C
+#define VDEC_E_DFE_CTRL1 0x1840
+#define VDEC_E_DFE_CTRL2 0x1844
+#define VDEC_E_DFE_CTRL3 0x1848
+#define VDEC_E_PLL_CTRL 0x184C
#define VDEC_E_PLL_CTRL_FAST 0x1850
-#define VDEC_E_HTL_CTRL 0x1854
-#define VDEC_E_SRC_CFG 0x1858
-#define VDEC_E_SC_STEP_SIZE 0x185C
+#define VDEC_E_HTL_CTRL 0x1854
+#define VDEC_E_SRC_CFG 0x1858
+#define VDEC_E_SC_STEP_SIZE 0x185C
#define VDEC_E_SC_CONVERGE_CTRL 0x1860
-#define VDEC_E_SC_LOOP_CTRL 0x1864
+#define VDEC_E_SC_LOOP_CTRL 0x1864
#define VDEC_E_COMB_2D_HFS_CFG 0x1868
#define VDEC_E_COMB_2D_HFD_CFG 0x186C
#define VDEC_E_COMB_2D_LF_CFG 0x1870
#define VDEC_E_COMB_2D_BLEND 0x1874
#define VDEC_E_COMB_MISC_CTRL 0x1878
-#define VDEC_E_COMB_FLAT_THRESH_CTRL 0x187C
-#define VDEC_E_COMB_TEST 0x1880
-#define VDEC_E_BP_MISC_CTRL 0x1884
-#define VDEC_E_VCR_DET_CTRL 0x1888
+#define VDEC_E_COMB_FLAT_THRESH_CTRL 0x187C
+#define VDEC_E_COMB_TEST 0x1880
+#define VDEC_E_BP_MISC_CTRL 0x1884
+#define VDEC_E_VCR_DET_CTRL 0x1888
#define VDEC_E_NOISE_DET_CTRL 0x188C
#define VDEC_E_COMB_FLAT_NOISE_CTRL 0x1890
-#define VDEC_E_VERSION 0x19F8
+#define VDEC_E_VERSION 0x19F8
#define VDEC_E_SOFT_RST_CTRL 0x19FC
/* Video Decoder F Registers */
-#define VDEC_F_MODE_CTRL 0x1A00
-#define VDEC_F_OUT_CTRL1 0x1A04
-#define VDEC_F_OUT_CTRL_NS 0x1A08
-#define VDEC_F_GEN_STAT 0x1A0C
+#define VDEC_F_MODE_CTRL 0x1A00
+#define VDEC_F_OUT_CTRL1 0x1A04
+#define VDEC_F_OUT_CTRL_NS 0x1A08
+#define VDEC_F_GEN_STAT 0x1A0C
#define VDEC_F_INT_STAT_MASK 0x1A10
-#define VDEC_F_LUMA_CTRL 0x1A14
-#define VDEC_F_CHROMA_CTRL 0x1A18
-#define VDEC_F_CRUSH_CTRL 0x1A1C
+#define VDEC_F_LUMA_CTRL 0x1A14
+#define VDEC_F_CHROMA_CTRL 0x1A18
+#define VDEC_F_CRUSH_CTRL 0x1A1C
#define VDEC_F_HORIZ_TIM_CTRL 0x1A20
#define VDEC_F_VERT_TIM_CTRL 0x1A24
#define VDEC_F_MISC_TIM_CTRL 0x1A28
-#define VDEC_F_FIELD_COUNT 0x1A2C
-#define VDEC_F_HSCALE_CTRL 0x1A30
-#define VDEC_F_VSCALE_CTRL 0x1A34
-#define VDEC_F_MAN_VGA_CTRL 0x1A38
-#define VDEC_F_MAN_AGC_CTRL 0x1A3C
-#define VDEC_F_DFE_CTRL1 0x1A40
-#define VDEC_F_DFE_CTRL2 0x1A44
-#define VDEC_F_DFE_CTRL3 0x1A48
-#define VDEC_F_PLL_CTRL 0x1A4C
+#define VDEC_F_FIELD_COUNT 0x1A2C
+#define VDEC_F_HSCALE_CTRL 0x1A30
+#define VDEC_F_VSCALE_CTRL 0x1A34
+#define VDEC_F_MAN_VGA_CTRL 0x1A38
+#define VDEC_F_MAN_AGC_CTRL 0x1A3C
+#define VDEC_F_DFE_CTRL1 0x1A40
+#define VDEC_F_DFE_CTRL2 0x1A44
+#define VDEC_F_DFE_CTRL3 0x1A48
+#define VDEC_F_PLL_CTRL 0x1A4C
#define VDEC_F_PLL_CTRL_FAST 0x1A50
-#define VDEC_F_HTL_CTRL 0x1A54
-#define VDEC_F_SRC_CFG 0x1A58
-#define VDEC_F_SC_STEP_SIZE 0x1A5C
+#define VDEC_F_HTL_CTRL 0x1A54
+#define VDEC_F_SRC_CFG 0x1A58
+#define VDEC_F_SC_STEP_SIZE 0x1A5C
#define VDEC_F_SC_CONVERGE_CTRL 0x1A60
-#define VDEC_F_SC_LOOP_CTRL 0x1A64
+#define VDEC_F_SC_LOOP_CTRL 0x1A64
#define VDEC_F_COMB_2D_HFS_CFG 0x1A68
#define VDEC_F_COMB_2D_HFD_CFG 0x1A6C
#define VDEC_F_COMB_2D_LF_CFG 0x1A70
#define VDEC_F_COMB_2D_BLEND 0x1A74
#define VDEC_F_COMB_MISC_CTRL 0x1A78
-#define VDEC_F_COMB_FLAT_THRESH_CTRL 0x1A7C
-#define VDEC_F_COMB_TEST 0x1A80
-#define VDEC_F_BP_MISC_CTRL 0x1A84
-#define VDEC_F_VCR_DET_CTRL 0x1A88
+#define VDEC_F_COMB_FLAT_THRESH_CTRL 0x1A7C
+#define VDEC_F_COMB_TEST 0x1A80
+#define VDEC_F_BP_MISC_CTRL 0x1A84
+#define VDEC_F_VCR_DET_CTRL 0x1A88
#define VDEC_F_NOISE_DET_CTRL 0x1A8C
#define VDEC_F_COMB_FLAT_NOISE_CTRL 0x1A90
-#define VDEC_F_VERSION 0x1BF8
+#define VDEC_F_VERSION 0x1BF8
#define VDEC_F_SOFT_RST_CTRL 0x1BFC
/* Video Decoder G Registers */
-#define VDEC_G_MODE_CTRL 0x1C00
-#define VDEC_G_OUT_CTRL1 0x1C04
-#define VDEC_G_OUT_CTRL_NS 0x1C08
-#define VDEC_G_GEN_STAT 0x1C0C
+#define VDEC_G_MODE_CTRL 0x1C00
+#define VDEC_G_OUT_CTRL1 0x1C04
+#define VDEC_G_OUT_CTRL_NS 0x1C08
+#define VDEC_G_GEN_STAT 0x1C0C
#define VDEC_G_INT_STAT_MASK 0x1C10
-#define VDEC_G_LUMA_CTRL 0x1C14
-#define VDEC_G_CHROMA_CTRL 0x1C18
-#define VDEC_G_CRUSH_CTRL 0x1C1C
+#define VDEC_G_LUMA_CTRL 0x1C14
+#define VDEC_G_CHROMA_CTRL 0x1C18
+#define VDEC_G_CRUSH_CTRL 0x1C1C
#define VDEC_G_HORIZ_TIM_CTRL 0x1C20
#define VDEC_G_VERT_TIM_CTRL 0x1C24
#define VDEC_G_MISC_TIM_CTRL 0x1C28
-#define VDEC_G_FIELD_COUNT 0x1C2C
-#define VDEC_G_HSCALE_CTRL 0x1C30
-#define VDEC_G_VSCALE_CTRL 0x1C34
-#define VDEC_G_MAN_VGA_CTRL 0x1C38
-#define VDEC_G_MAN_AGC_CTRL 0x1C3C
-#define VDEC_G_DFE_CTRL1 0x1C40
-#define VDEC_G_DFE_CTRL2 0x1C44
-#define VDEC_G_DFE_CTRL3 0x1C48
-#define VDEC_G_PLL_CTRL 0x1C4C
+#define VDEC_G_FIELD_COUNT 0x1C2C
+#define VDEC_G_HSCALE_CTRL 0x1C30
+#define VDEC_G_VSCALE_CTRL 0x1C34
+#define VDEC_G_MAN_VGA_CTRL 0x1C38
+#define VDEC_G_MAN_AGC_CTRL 0x1C3C
+#define VDEC_G_DFE_CTRL1 0x1C40
+#define VDEC_G_DFE_CTRL2 0x1C44
+#define VDEC_G_DFE_CTRL3 0x1C48
+#define VDEC_G_PLL_CTRL 0x1C4C
#define VDEC_G_PLL_CTRL_FAST 0x1C50
-#define VDEC_G_HTL_CTRL 0x1C54
-#define VDEC_G_SRC_CFG 0x1C58
-#define VDEC_G_SC_STEP_SIZE 0x1C5C
+#define VDEC_G_HTL_CTRL 0x1C54
+#define VDEC_G_SRC_CFG 0x1C58
+#define VDEC_G_SC_STEP_SIZE 0x1C5C
#define VDEC_G_SC_CONVERGE_CTRL 0x1C60
-#define VDEC_G_SC_LOOP_CTRL 0x1C64
+#define VDEC_G_SC_LOOP_CTRL 0x1C64
#define VDEC_G_COMB_2D_HFS_CFG 0x1C68
#define VDEC_G_COMB_2D_HFD_CFG 0x1C6C
#define VDEC_G_COMB_2D_LF_CFG 0x1C70
#define VDEC_G_COMB_2D_BLEND 0x1C74
#define VDEC_G_COMB_MISC_CTRL 0x1C78
-#define VDEC_G_COMB_FLAT_THRESH_CTRL 0x1C7C
-#define VDEC_G_COMB_TEST 0x1C80
-#define VDEC_G_BP_MISC_CTRL 0x1C84
-#define VDEC_G_VCR_DET_CTRL 0x1C88
+#define VDEC_G_COMB_FLAT_THRESH_CTRL 0x1C7C
+#define VDEC_G_COMB_TEST 0x1C80
+#define VDEC_G_BP_MISC_CTRL 0x1C84
+#define VDEC_G_VCR_DET_CTRL 0x1C88
#define VDEC_G_NOISE_DET_CTRL 0x1C8C
#define VDEC_G_COMB_FLAT_NOISE_CTRL 0x1C90
-#define VDEC_G_VERSION 0x1DF8
+#define VDEC_G_VERSION 0x1DF8
#define VDEC_G_SOFT_RST_CTRL 0x1DFC
-/* Video Decoder H Registers */
-#define VDEC_H_MODE_CTRL 0x1E00
-#define VDEC_H_OUT_CTRL1 0x1E04
-#define VDEC_H_OUT_CTRL_NS 0x1E08
-#define VDEC_H_GEN_STAT 0x1E0C
+/* Video Decoder H Registers */
+#define VDEC_H_MODE_CTRL 0x1E00
+#define VDEC_H_OUT_CTRL1 0x1E04
+#define VDEC_H_OUT_CTRL_NS 0x1E08
+#define VDEC_H_GEN_STAT 0x1E0C
#define VDEC_H_INT_STAT_MASK 0x1E1E
-#define VDEC_H_LUMA_CTRL 0x1E14
-#define VDEC_H_CHROMA_CTRL 0x1E18
-#define VDEC_H_CRUSH_CTRL 0x1E1C
+#define VDEC_H_LUMA_CTRL 0x1E14
+#define VDEC_H_CHROMA_CTRL 0x1E18
+#define VDEC_H_CRUSH_CTRL 0x1E1C
#define VDEC_H_HORIZ_TIM_CTRL 0x1E20
#define VDEC_H_VERT_TIM_CTRL 0x1E24
#define VDEC_H_MISC_TIM_CTRL 0x1E28
-#define VDEC_H_FIELD_COUNT 0x1E2C
-#define VDEC_H_HSCALE_CTRL 0x1E30
-#define VDEC_H_VSCALE_CTRL 0x1E34
-#define VDEC_H_MAN_VGA_CTRL 0x1E38
-#define VDEC_H_MAN_AGC_CTRL 0x1E3C
-#define VDEC_H_DFE_CTRL1 0x1E40
-#define VDEC_H_DFE_CTRL2 0x1E44
-#define VDEC_H_DFE_CTRL3 0x1E48
-#define VDEC_H_PLL_CTRL 0x1E4C
+#define VDEC_H_FIELD_COUNT 0x1E2C
+#define VDEC_H_HSCALE_CTRL 0x1E30
+#define VDEC_H_VSCALE_CTRL 0x1E34
+#define VDEC_H_MAN_VGA_CTRL 0x1E38
+#define VDEC_H_MAN_AGC_CTRL 0x1E3C
+#define VDEC_H_DFE_CTRL1 0x1E40
+#define VDEC_H_DFE_CTRL2 0x1E44
+#define VDEC_H_DFE_CTRL3 0x1E48
+#define VDEC_H_PLL_CTRL 0x1E4C
#define VDEC_H_PLL_CTRL_FAST 0x1E50
-#define VDEC_H_HTL_CTRL 0x1E54
-#define VDEC_H_SRC_CFG 0x1E58
-#define VDEC_H_SC_STEP_SIZE 0x1E5C
+#define VDEC_H_HTL_CTRL 0x1E54
+#define VDEC_H_SRC_CFG 0x1E58
+#define VDEC_H_SC_STEP_SIZE 0x1E5C
#define VDEC_H_SC_CONVERGE_CTRL 0x1E60
-#define VDEC_H_SC_LOOP_CTRL 0x1E64
+#define VDEC_H_SC_LOOP_CTRL 0x1E64
#define VDEC_H_COMB_2D_HFS_CFG 0x1E68
#define VDEC_H_COMB_2D_HFD_CFG 0x1E6C
#define VDEC_H_COMB_2D_LF_CFG 0x1E70
#define VDEC_H_COMB_2D_BLEND 0x1E74
#define VDEC_H_COMB_MISC_CTRL 0x1E78
-#define VDEC_H_COMB_FLAT_THRESH_CTRL 0x1E7C
-#define VDEC_H_COMB_TEST 0x1E80
-#define VDEC_H_BP_MISC_CTRL 0x1E84
-#define VDEC_H_VCR_DET_CTRL 0x1E88
+#define VDEC_H_COMB_FLAT_THRESH_CTRL 0x1E7C
+#define VDEC_H_COMB_TEST 0x1E80
+#define VDEC_H_BP_MISC_CTRL 0x1E84
+#define VDEC_H_VCR_DET_CTRL 0x1E88
#define VDEC_H_NOISE_DET_CTRL 0x1E8C
#define VDEC_H_COMB_FLAT_NOISE_CTRL 0x1E90
-#define VDEC_H_VERSION 0x1FF8
+#define VDEC_H_VERSION 0x1FF8
#define VDEC_H_SOFT_RST_CTRL 0x1FFC
/*****************************************************************************/
/* LUMA_CTRL register fields */
-#define VDEC_A_BRITE_CTRL 0x1014
+#define VDEC_A_BRITE_CTRL 0x1014
#define VDEC_A_CNTRST_CTRL 0x1015
#define VDEC_A_PEAK_SEL 0x1016
diff --git a/drivers/media/video/cx25821/cx25821-medusa-video.c b/drivers/media/video/cx25821/cx25821-medusa-video.c
index fc780d0908dc..298a68d98c2f 100644
--- a/drivers/media/video/cx25821/cx25821-medusa-video.c
+++ b/drivers/media/video/cx25821/cx25821-medusa-video.c
@@ -99,82 +99,67 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev)
for (i = 0; i < MAX_DECODERS; i++) {
/* set video format NTSC-M */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
- &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ MODE_CTRL + (0x200 * i), &tmp);
value &= 0xFFFFFFF0;
/* enable the fast locking mode bit[16] */
value |= 0x10001;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
- value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ MODE_CTRL + (0x200 * i), value);
/* resolution NTSC 720x480 */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- HORIZ_TIM_CTRL + (0x200 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ HORIZ_TIM_CTRL + (0x200 * i), &tmp);
value &= 0x00C00C00;
value |= 0x612D0074;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- HORIZ_TIM_CTRL + (0x200 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ HORIZ_TIM_CTRL + (0x200 * i), value);
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- VERT_TIM_CTRL + (0x200 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ VERT_TIM_CTRL + (0x200 * i), &tmp);
value &= 0x00C00C00;
value |= 0x1C1E001A; /* vblank_cnt + 2 to get camera ID */
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- VERT_TIM_CTRL + (0x200 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ VERT_TIM_CTRL + (0x200 * i), value);
/* chroma subcarrier step size */
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- SC_STEP_SIZE + (0x200 * i), 0x43E00000);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ SC_STEP_SIZE + (0x200 * i), 0x43E00000);
/* enable VIP optional active */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- OUT_CTRL_NS + (0x200 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ OUT_CTRL_NS + (0x200 * i), &tmp);
value &= 0xFFFBFFFF;
value |= 0x00040000;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- OUT_CTRL_NS + (0x200 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ OUT_CTRL_NS + (0x200 * i), value);
/* enable VIP optional active (VIP_OPT_AL) for direct output. */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
- &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ OUT_CTRL1 + (0x200 * i), &tmp);
value &= 0xFFFBFFFF;
value |= 0x00040000;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
- value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ OUT_CTRL1 + (0x200 * i), value);
/*
* clear VPRES_VERT_EN bit, fixes the chroma run away problem
* when the input switching rate < 16 fields
*/
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- MISC_TIM_CTRL + (0x200 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ MISC_TIM_CTRL + (0x200 * i), &tmp);
/* disable special play detection */
value = setBitAtPos(value, 14);
value = clearBitAtPos(value, 15);
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- MISC_TIM_CTRL + (0x200 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ MISC_TIM_CTRL + (0x200 * i), value);
/* set vbi_gate_en to 0 */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
- &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DFE_CTRL1 + (0x200 * i), &tmp);
value = clearBitAtPos(value, 29);
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
- value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DFE_CTRL1 + (0x200 * i), value);
/* Enable the generation of blue field output if no video */
medusa_enable_bluefield_output(dev, i, 1);
@@ -182,61 +167,49 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev)
for (i = 0; i < MAX_ENCODERS; i++) {
/* NTSC hclock */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- DENC_A_REG_1 + (0x100 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DENC_A_REG_1 + (0x100 * i), &tmp);
value &= 0xF000FC00;
value |= 0x06B402D0;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_1 + (0x100 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_1 + (0x100 * i), value);
/* burst begin and burst end */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- DENC_A_REG_2 + (0x100 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DENC_A_REG_2 + (0x100 * i), &tmp);
value &= 0xFF000000;
value |= 0x007E9054;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_2 + (0x100 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_2 + (0x100 * i), value);
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- DENC_A_REG_3 + (0x100 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DENC_A_REG_3 + (0x100 * i), &tmp);
value &= 0xFC00FE00;
value |= 0x00EC00F0;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_3 + (0x100 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_3 + (0x100 * i), value);
/* set NTSC vblank, no phase alternation, 7.5 IRE pedestal */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- DENC_A_REG_4 + (0x100 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DENC_A_REG_4 + (0x100 * i), &tmp);
value &= 0x00FCFFFF;
value |= 0x13020000;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_4 + (0x100 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_4 + (0x100 * i), value);
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- DENC_A_REG_5 + (0x100 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DENC_A_REG_5 + (0x100 * i), &tmp);
value &= 0xFFFF0000;
value |= 0x0000E575;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_5 + (0x100 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_5 + (0x100 * i), value);
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_6 + (0x100 * i), 0x009A89C1);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_6 + (0x100 * i), 0x009A89C1);
/* Subcarrier Increment */
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_7 + (0x100 * i), 0x21F07C1F);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_7 + (0x100 * i), 0x21F07C1F);
}
/* set picture resolutions */
@@ -261,34 +234,27 @@ static int medusa_PALCombInit(struct cx25821_dev *dev, int dec)
u32 value = 0, tmp = 0;
/* Setup for 2D threshold */
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFS_CFG + (0x200 * dec),
- 0x20002861);
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFD_CFG + (0x200 * dec),
- 0x20002861);
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_LF_CFG + (0x200 * dec),
- 0x200A1023);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ COMB_2D_HFS_CFG + (0x200 * dec), 0x20002861);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ COMB_2D_HFD_CFG + (0x200 * dec), 0x20002861);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ COMB_2D_LF_CFG + (0x200 * dec), 0x200A1023);
/* Setup flat chroma and luma thresholds */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp);
value &= 0x06230000;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- COMB_FLAT_THRESH_CTRL + (0x200 * dec), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ COMB_FLAT_THRESH_CTRL + (0x200 * dec), value);
/* set comb 2D blend */
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_BLEND + (0x200 * dec),
- 0x210F0F0F);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ COMB_2D_BLEND + (0x200 * dec), 0x210F0F0F);
/* COMB MISC CONTROL */
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], COMB_MISC_CTRL + (0x200 * dec),
- 0x41120A7F);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ COMB_MISC_CTRL + (0x200 * dec), 0x41120A7F);
return ret_val;
}
@@ -304,83 +270,68 @@ static int medusa_initialize_pal(struct cx25821_dev *dev)
for (i = 0; i < MAX_DECODERS; i++) {
/* set video format PAL-BDGHI */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
- &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ MODE_CTRL + (0x200 * i), &tmp);
value &= 0xFFFFFFF0;
/* enable the fast locking mode bit[16] */
value |= 0x10004;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
- value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ MODE_CTRL + (0x200 * i), value);
/* resolution PAL 720x576 */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- HORIZ_TIM_CTRL + (0x200 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ HORIZ_TIM_CTRL + (0x200 * i), &tmp);
value &= 0x00C00C00;
value |= 0x632D007D;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- HORIZ_TIM_CTRL + (0x200 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ HORIZ_TIM_CTRL + (0x200 * i), value);
/* vblank656_cnt=x26, vactive_cnt=240h, vblank_cnt=x24 */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- VERT_TIM_CTRL + (0x200 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ VERT_TIM_CTRL + (0x200 * i), &tmp);
value &= 0x00C00C00;
value |= 0x28240026; /* vblank_cnt + 2 to get camera ID */
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- VERT_TIM_CTRL + (0x200 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ VERT_TIM_CTRL + (0x200 * i), value);
/* chroma subcarrier step size */
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- SC_STEP_SIZE + (0x200 * i), 0x5411E2D0);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ SC_STEP_SIZE + (0x200 * i), 0x5411E2D0);
/* enable VIP optional active */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- OUT_CTRL_NS + (0x200 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ OUT_CTRL_NS + (0x200 * i), &tmp);
value &= 0xFFFBFFFF;
value |= 0x00040000;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- OUT_CTRL_NS + (0x200 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ OUT_CTRL_NS + (0x200 * i), value);
/* enable VIP optional active (VIP_OPT_AL) for direct output. */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
- &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ OUT_CTRL1 + (0x200 * i), &tmp);
value &= 0xFFFBFFFF;
value |= 0x00040000;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
- value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ OUT_CTRL1 + (0x200 * i), value);
/*
* clear VPRES_VERT_EN bit, fixes the chroma run away problem
* when the input switching rate < 16 fields
*/
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- MISC_TIM_CTRL + (0x200 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ MISC_TIM_CTRL + (0x200 * i), &tmp);
/* disable special play detection */
value = setBitAtPos(value, 14);
value = clearBitAtPos(value, 15);
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- MISC_TIM_CTRL + (0x200 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ MISC_TIM_CTRL + (0x200 * i), value);
/* set vbi_gate_en to 0 */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
- &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DFE_CTRL1 + (0x200 * i), &tmp);
value = clearBitAtPos(value, 29);
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
- value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DFE_CTRL1 + (0x200 * i), value);
medusa_PALCombInit(dev, i);
@@ -390,62 +341,50 @@ static int medusa_initialize_pal(struct cx25821_dev *dev)
for (i = 0; i < MAX_ENCODERS; i++) {
/* PAL hclock */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- DENC_A_REG_1 + (0x100 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DENC_A_REG_1 + (0x100 * i), &tmp);
value &= 0xF000FC00;
value |= 0x06C002D0;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_1 + (0x100 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_1 + (0x100 * i), value);
/* burst begin and burst end */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- DENC_A_REG_2 + (0x100 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DENC_A_REG_2 + (0x100 * i), &tmp);
value &= 0xFF000000;
value |= 0x007E9754;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_2 + (0x100 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_2 + (0x100 * i), value);
/* hblank and vactive */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- DENC_A_REG_3 + (0x100 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DENC_A_REG_3 + (0x100 * i), &tmp);
value &= 0xFC00FE00;
value |= 0x00FC0120;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_3 + (0x100 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_3 + (0x100 * i), value);
/* set PAL vblank, phase alternation, 0 IRE pedestal */
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- DENC_A_REG_4 + (0x100 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DENC_A_REG_4 + (0x100 * i), &tmp);
value &= 0x00FCFFFF;
value |= 0x14010000;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_4 + (0x100 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_4 + (0x100 * i), value);
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- DENC_A_REG_5 + (0x100 * i), &tmp);
+ value = cx25821_i2c_read(&dev->i2c_bus[0],
+ DENC_A_REG_5 + (0x100 * i), &tmp);
value &= 0xFFFF0000;
value |= 0x0000F078;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_5 + (0x100 * i), value);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_5 + (0x100 * i), value);
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_6 + (0x100 * i), 0x00A493CF);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_6 + (0x100 * i), 0x00A493CF);
/* Subcarrier Increment */
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- DENC_A_REG_7 + (0x100 * i), 0x2A098ACB);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ DENC_A_REG_7 + (0x100 * i), 0x2A098ACB);
}
/* set picture resolutions */
@@ -499,7 +438,7 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
mutex_lock(&dev->lock);
- /* validate the width - cannot be negative */
+ /* validate the width */
if (width > MAX_WIDTH) {
pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n",
__func__, width, MAX_WIDTH);
@@ -543,12 +482,10 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
for (; decoder < decoder_count; decoder++) {
/* write scaling values for each decoder */
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- HSCALE_CTRL + (0x200 * decoder), hscale);
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0],
- VSCALE_CTRL + (0x200 * decoder), vscale);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ HSCALE_CTRL + (0x200 * decoder), hscale);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ VSCALE_CTRL + (0x200 * decoder), vscale);
}
mutex_unlock(&dev->lock);
@@ -606,8 +543,8 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder,
}
/* Map to Medusa register setting */
-static int mapM(int srcMin,
- int srcMax, int srcVal, int dstMin, int dstMax, int *dstVal)
+static int mapM(int srcMin, int srcMax, int srcVal, int dstMin, int dstMax,
+ int *dstVal)
{
int numerator;
int denominator;
@@ -654,23 +591,19 @@ int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder)
u32 val = 0, tmp = 0;
mutex_lock(&dev->lock);
- if ((brightness > VIDEO_PROCAMP_MAX)
- || (brightness < VIDEO_PROCAMP_MIN)) {
+ if ((brightness > VIDEO_PROCAMP_MAX) ||
+ (brightness < VIDEO_PROCAMP_MIN)) {
mutex_unlock(&dev->lock);
return -1;
}
- ret_val =
- mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness,
- SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value);
+ ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness,
+ SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value);
value = convert_to_twos(value, 8);
- val =
- cx25821_i2c_read(&dev->i2c_bus[0],
- VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp);
+ val = cx25821_i2c_read(&dev->i2c_bus[0],
+ VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp);
val &= 0xFFFFFF00;
- ret_val |=
- cx25821_i2c_write(&dev->i2c_bus[0],
- VDEC_A_BRITE_CTRL + (0x200 * decoder),
- val | value);
+ ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+ VDEC_A_BRITE_CTRL + (0x200 * decoder), val | value);
mutex_unlock(&dev->lock);
return ret_val;
}
@@ -688,17 +621,13 @@ int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder)
return -1;
}
- ret_val =
- mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast,
- UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value);
- val =
- cx25821_i2c_read(&dev->i2c_bus[0],
- VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp);
+ ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast,
+ UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value);
+ val = cx25821_i2c_read(&dev->i2c_bus[0],
+ VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp);
val &= 0xFFFFFF00;
- ret_val |=
- cx25821_i2c_write(&dev->i2c_bus[0],
- VDEC_A_CNTRST_CTRL + (0x200 * decoder),
- val | value);
+ ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+ VDEC_A_CNTRST_CTRL + (0x200 * decoder), val | value);
mutex_unlock(&dev->lock);
return ret_val;
@@ -717,19 +646,16 @@ int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder)
return -1;
}
- ret_val =
- mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue, SIGNED_BYTE_MIN,
- SIGNED_BYTE_MAX, &value);
+ ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue,
+ SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value);
value = convert_to_twos(value, 8);
- val =
- cx25821_i2c_read(&dev->i2c_bus[0],
- VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp);
+ val = cx25821_i2c_read(&dev->i2c_bus[0],
+ VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp);
val &= 0xFFFFFF00;
- ret_val |=
- cx25821_i2c_write(&dev->i2c_bus[0],
- VDEC_A_HUE_CTRL + (0x200 * decoder), val | value);
+ ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+ VDEC_A_HUE_CTRL + (0x200 * decoder), val | value);
mutex_unlock(&dev->lock);
return ret_val;
@@ -743,33 +669,26 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder)
mutex_lock(&dev->lock);
- if ((saturation > VIDEO_PROCAMP_MAX)
- || (saturation < VIDEO_PROCAMP_MIN)) {
+ if ((saturation > VIDEO_PROCAMP_MAX) ||
+ (saturation < VIDEO_PROCAMP_MIN)) {
mutex_unlock(&dev->lock);
return -1;
}
- ret_val =
- mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation,
- UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value);
+ ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation,
+ UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value);
- val =
- cx25821_i2c_read(&dev->i2c_bus[0],
- VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp);
+ val = cx25821_i2c_read(&dev->i2c_bus[0],
+ VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp);
val &= 0xFFFFFF00;
- ret_val |=
- cx25821_i2c_write(&dev->i2c_bus[0],
- VDEC_A_USAT_CTRL + (0x200 * decoder),
- val | value);
-
- val =
- cx25821_i2c_read(&dev->i2c_bus[0],
- VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp);
+ ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+ VDEC_A_USAT_CTRL + (0x200 * decoder), val | value);
+
+ val = cx25821_i2c_read(&dev->i2c_bus[0],
+ VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp);
val &= 0xFFFFFF00;
- ret_val |=
- cx25821_i2c_write(&dev->i2c_bus[0],
- VDEC_A_VSAT_CTRL + (0x200 * decoder),
- val | value);
+ ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+ VDEC_A_VSAT_CTRL + (0x200 * decoder), val | value);
mutex_unlock(&dev->lock);
return ret_val;
@@ -830,9 +749,8 @@ int medusa_video_init(struct cx25821_dev *dev)
/* select AFE clock to output mode */
value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
value &= 0x83FFFFFF;
- ret_val =
- cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
- value | 0x10000000);
+ ret_val = cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
+ value | 0x10000000);
if (ret_val < 0)
goto error;
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
index 2a724ddfa53f..5a157cf4a95e 100644
--- a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
+++ b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
@@ -65,9 +65,8 @@ static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev,
*(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset);
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
- if ((lines <= NTSC_FIELD_HEIGHT)
- || (line < (NTSC_FIELD_HEIGHT - 1))
- || !(dev->_isNTSC_ch2)) {
+ if ((lines <= NTSC_FIELD_HEIGHT) ||
+ (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) {
offset += dist_betwn_starts;
}
}
@@ -85,7 +84,7 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
{
unsigned int line, i;
struct sram_channel *sram_ch =
- dev->channels[dev->_channel2_upstream_select].sram_channels;
+ dev->channels[dev->_channel2_upstream_select].sram_channels;
int dist_betwn_starts = bpl * 2;
/* sync instruction */
@@ -103,9 +102,8 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
*(rp++) = cpu_to_le32(databuf_phys_addr + offset);
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
- if ((lines <= NTSC_FIELD_HEIGHT)
- || (line < (NTSC_FIELD_HEIGHT - 1))
- || !(dev->_isNTSC_ch2)) {
+ if ((lines <= NTSC_FIELD_HEIGHT) ||
+ (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) {
offset += dist_betwn_starts;
}
@@ -173,7 +171,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
fifo_enable = FIFO_DISABLE;
- /* Even field */
+ /* Even field */
rp = cx25821_risc_field_upstream_ch2(dev, rp,
dev->_data_buf_phys_addr_ch2 + databuf_offset,
bottom_offset, 0x200, bpl, singlefield_lines,
@@ -189,9 +187,9 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
}
/*
- Loop to 2ndFrameRISC or to Start of
- Risc program & generate IRQ
- */
+ * Loop to 2ndFrameRISC or to Start of
+ * Risc program & generate IRQ
+ */
*(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
*(rp++) = cpu_to_le32(risc_phys_jump_addr);
*(rp++) = cpu_to_le32(0);
@@ -203,7 +201,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
{
struct sram_channel *sram_ch =
- dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels;
+ dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels;
u32 tmp = 0;
if (!dev->_is_running_ch2) {
@@ -262,9 +260,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
struct file *myfile;
int frame_index_temp = dev->_frame_index_ch2;
int i = 0;
- int line_size =
- (dev->_pixel_format_ch2 ==
- PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ;
+ int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ?
+ Y411_LINE_SZ : Y422_LINE_SZ;
int frame_size = 0;
int frame_offset = 0;
ssize_t vfs_read_retval = 0;
@@ -277,14 +274,11 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
return 0;
if (dev->_isNTSC_ch2) {
- frame_size =
- (line_size ==
- Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 :
- FRAME_SIZE_NTSC_Y422;
+ frame_size = (line_size == Y411_LINE_SZ) ?
+ FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
} else {
- frame_size =
- (line_size ==
- Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
+ frame_size = (line_size == Y411_LINE_SZ) ?
+ FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
}
frame_offset = (frame_index_temp > 0) ? frame_size : 0;
@@ -318,14 +312,14 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
for (i = 0; i < dev->_lines_count_ch2; i++) {
pos = file_offset;
- vfs_read_retval =
- vfs_read(myfile, mybuf, line_size, &pos);
+ vfs_read_retval = vfs_read(myfile, mybuf, line_size,
+ &pos);
if (vfs_read_retval > 0 && vfs_read_retval == line_size
&& dev->_data_buf_virt_addr_ch2 != NULL) {
memcpy((void *)(dev->_data_buf_virt_addr_ch2 +
frame_offset / 4), mybuf,
- vfs_read_retval);
+ vfs_read_retval);
}
file_offset += vfs_read_retval;
@@ -341,8 +335,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (i > 0)
dev->_frame_count_ch2++;
- dev->_file_status_ch2 =
- (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+ dev->_file_status_ch2 = (vfs_read_retval == line_size) ?
+ IN_PROGRESS : END_OF_FILE;
set_fs(old_fs);
filp_close(myfile, NULL);
@@ -353,8 +347,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
static void cx25821_vidups_handler_ch2(struct work_struct *work)
{
- struct cx25821_dev *dev =
- container_of(work, struct cx25821_dev, _irq_work_entry_ch2);
+ struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
+ _irq_work_entry_ch2);
if (!dev) {
pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
@@ -362,18 +356,16 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work)
return;
}
- cx25821_get_frame_ch2(dev,
- dev->channels[dev->
- _channel2_upstream_select].sram_channels);
+ cx25821_get_frame_ch2(dev, dev->channels[dev->
+ _channel2_upstream_select].sram_channels);
}
int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
{
struct file *myfile;
int i = 0, j = 0;
- int line_size =
- (dev->_pixel_format_ch2 ==
- PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ;
+ int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ?
+ Y411_LINE_SZ : Y422_LINE_SZ;
ssize_t vfs_read_retval = 0;
char mybuf[line_size];
loff_t pos;
@@ -410,16 +402,16 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
for (i = 0; i < dev->_lines_count_ch2; i++) {
pos = offset;
- vfs_read_retval =
- vfs_read(myfile, mybuf, line_size, &pos);
+ vfs_read_retval = vfs_read(myfile, mybuf,
+ line_size, &pos);
- if (vfs_read_retval > 0
- && vfs_read_retval == line_size
- && dev->_data_buf_virt_addr_ch2 != NULL) {
+ if (vfs_read_retval > 0 &&
+ vfs_read_retval == line_size &&
+ dev->_data_buf_virt_addr_ch2 != NULL) {
memcpy((void *)(dev->
_data_buf_virt_addr_ch2
+ offset / 4), mybuf,
- vfs_read_retval);
+ vfs_read_retval);
}
offset += vfs_read_retval;
@@ -438,8 +430,8 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
break;
}
- dev->_file_status_ch2 =
- (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+ dev->_file_status_ch2 = (vfs_read_retval == line_size) ?
+ IN_PROGRESS : END_OF_FILE;
set_fs(old_fs);
myfile->f_pos = 0;
@@ -463,9 +455,8 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
dev->_dma_phys_addr_ch2);
}
- dev->_dma_virt_addr_ch2 =
- pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size_ch2,
- &dma_addr);
+ dev->_dma_virt_addr_ch2 = pci_alloc_consistent(dev->pci,
+ dev->upstream_riscbuf_size_ch2, &dma_addr);
dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2;
dev->_dma_phys_start_addr_ch2 = dma_addr;
dev->_dma_phys_addr_ch2 = dma_addr;
@@ -485,9 +476,8 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
dev->_data_buf_phys_addr_ch2);
}
/* For Video Data buffer allocation */
- dev->_data_buf_virt_addr_ch2 =
- pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2,
- &data_dma_addr);
+ dev->_data_buf_virt_addr_ch2 = pci_alloc_consistent(dev->pci,
+ dev->upstream_databuf_size_ch2, &data_dma_addr);
dev->_data_buf_phys_addr_ch2 = data_dma_addr;
dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2;
@@ -563,8 +553,8 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
else
line_size_in_bytes = Y422_LINE_SZ;
risc_phys_jump_addr =
- dev->_dma_phys_start_addr_ch2 +
- odd_risc_prog_size;
+ dev->_dma_phys_start_addr_ch2 +
+ odd_risc_prog_size;
rp = cx25821_update_riscprogram_ch2(dev,
dev->_dma_virt_start_addr_ch2,
@@ -612,11 +602,9 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
vid_status = cx_read(sram_ch->int_stat);
/* Only deal with our interrupt */
- if (vid_status) {
- handled =
- cx25821_video_upstream_irq_ch2(dev, channel_num,
- vid_status);
- }
+ if (vid_status)
+ handled = cx25821_video_upstream_irq_ch2(dev, channel_num,
+ vid_status);
if (handled < 0)
cx25821_stop_upstream_video_ch2(dev);
@@ -691,8 +679,7 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
tmp = cx_read(sram_ch->int_msk);
cx_write(sram_ch->int_msk, tmp |= _intr_msk);
- err =
- request_irq(dev->pci->irq, cx25821_upstream_irq_ch2,
+ err = request_irq(dev->pci->irq, cx25821_upstream_irq_ch2,
IRQF_SHARED, dev->name, dev);
if (err < 0) {
pr_err("%s: can't get upstream IRQ %d\n",
@@ -752,45 +739,38 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
dev->_file_status_ch2 = RESET_STATUS;
dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576;
dev->_pixel_format_ch2 = pixel_format;
- dev->_line_size_ch2 =
- (dev->_pixel_format_ch2 ==
- PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
+ dev->_line_size_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_422) ?
+ (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ;
- risc_buffer_size =
- dev->_isNTSC_ch2 ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
+ risc_buffer_size = dev->_isNTSC_ch2 ?
+ NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
if (dev->input_filename_ch2) {
str_length = strlen(dev->input_filename_ch2);
- dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL);
+ dev->_filename_ch2 = kmemdup(dev->input_filename_ch2,
+ str_length + 1, GFP_KERNEL);
if (!dev->_filename_ch2)
goto error;
-
- memcpy(dev->_filename_ch2, dev->input_filename_ch2,
- str_length + 1);
} else {
str_length = strlen(dev->_defaultname_ch2);
- dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL);
+ dev->_filename_ch2 = kmemdup(dev->_defaultname_ch2,
+ str_length + 1, GFP_KERNEL);
if (!dev->_filename_ch2)
goto error;
-
- memcpy(dev->_filename_ch2, dev->_defaultname_ch2,
- str_length + 1);
}
/* Default if filename is empty string */
if (strcmp(dev->input_filename_ch2, "") == 0) {
if (dev->_isNTSC_ch2) {
- dev->_filename_ch2 =
- (dev->_pixel_format_ch2 ==
- PIXEL_FRMT_411) ? "/root/vid411.yuv" :
- "/root/vidtest.yuv";
+ dev->_filename_ch2 = (dev->_pixel_format_ch2 ==
+ PIXEL_FRMT_411) ? "/root/vid411.yuv" :
+ "/root/vidtest.yuv";
} else {
- dev->_filename_ch2 =
- (dev->_pixel_format_ch2 ==
- PIXEL_FRMT_411) ? "/root/pal411.yuv" :
- "/root/pal422.yuv";
+ dev->_filename_ch2 = (dev->_pixel_format_ch2 ==
+ PIXEL_FRMT_411) ? "/root/pal411.yuv" :
+ "/root/pal422.yuv";
}
}
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream.c b/drivers/media/video/cx25821/cx25821-video-upstream.c
index c0b80068f468..21e7d657f049 100644
--- a/drivers/media/video/cx25821/cx25821-video-upstream.c
+++ b/drivers/media/video/cx25821/cx25821-video-upstream.c
@@ -136,7 +136,7 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp,
{
unsigned int line, i;
struct sram_channel *sram_ch =
- dev->channels[dev->_channel_upstream_select].sram_channels;
+ dev->channels[dev->_channel_upstream_select].sram_channels;
int dist_betwn_starts = bpl * 2;
/* sync instruction */
@@ -194,15 +194,12 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
if (dev->_isNTSC) {
odd_num_lines = singlefield_lines + 1;
risc_program_size = FRAME1_VID_PROG_SIZE;
- frame_size =
- (bpl ==
- Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 :
- FRAME_SIZE_NTSC_Y422;
+ frame_size = (bpl == Y411_LINE_SZ) ?
+ FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
} else {
risc_program_size = PAL_VID_PROG_SIZE;
- frame_size =
- (bpl ==
- Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
+ frame_size = (bpl == Y411_LINE_SZ) ?
+ FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
}
/* Virtual address of Risc buffer program */
@@ -214,13 +211,9 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
if (UNSET != top_offset) {
fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE;
rp = cx25821_risc_field_upstream(dev, rp,
- dev->
- _data_buf_phys_addr +
- databuf_offset,
- top_offset, 0, bpl,
- odd_num_lines,
- fifo_enable,
- ODD_FIELD);
+ dev->_data_buf_phys_addr +
+ databuf_offset, top_offset, 0, bpl,
+ odd_num_lines, fifo_enable, ODD_FIELD);
}
fifo_enable = FIFO_DISABLE;
@@ -234,8 +227,8 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
if (frame == 0) {
risc_flag = RISC_CNT_RESET;
- risc_phys_jump_addr =
- dev->_dma_phys_start_addr + risc_program_size;
+ risc_phys_jump_addr = dev->_dma_phys_start_addr +
+ risc_program_size;
} else {
risc_phys_jump_addr = dev->_dma_phys_start_addr;
risc_flag = RISC_CNT_INC;
@@ -255,7 +248,7 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev)
{
struct sram_channel *sram_ch =
- dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels;
+ dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels;
u32 tmp = 0;
if (!dev->_is_running) {
@@ -312,9 +305,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
struct file *myfile;
int frame_index_temp = dev->_frame_index;
int i = 0;
- int line_size =
- (dev->_pixel_format ==
- PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ;
+ int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ?
+ Y411_LINE_SZ : Y422_LINE_SZ;
int frame_size = 0;
int frame_offset = 0;
ssize_t vfs_read_retval = 0;
@@ -326,16 +318,12 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (dev->_file_status == END_OF_FILE)
return 0;
- if (dev->_isNTSC) {
- frame_size =
- (line_size ==
- Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 :
- FRAME_SIZE_NTSC_Y422;
- } else {
- frame_size =
- (line_size ==
- Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
- }
+ if (dev->_isNTSC)
+ frame_size = (line_size == Y411_LINE_SZ) ?
+ FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
+ else
+ frame_size = (line_size == Y411_LINE_SZ) ?
+ FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
frame_offset = (frame_index_temp > 0) ? frame_size : 0;
file_offset = dev->_frame_count * frame_size;
@@ -369,8 +357,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
for (i = 0; i < dev->_lines_count; i++) {
pos = file_offset;
- vfs_read_retval =
- vfs_read(myfile, mybuf, line_size, &pos);
+ vfs_read_retval = vfs_read(myfile, mybuf, line_size,
+ &pos);
if (vfs_read_retval > 0 && vfs_read_retval == line_size
&& dev->_data_buf_virt_addr != NULL) {
@@ -392,8 +380,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (i > 0)
dev->_frame_count++;
- dev->_file_status =
- (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+ dev->_file_status = (vfs_read_retval == line_size) ?
+ IN_PROGRESS : END_OF_FILE;
set_fs(old_fs);
filp_close(myfile, NULL);
@@ -404,8 +392,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
static void cx25821_vidups_handler(struct work_struct *work)
{
- struct cx25821_dev *dev =
- container_of(work, struct cx25821_dev, _irq_work_entry);
+ struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
+ _irq_work_entry);
if (!dev) {
pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
@@ -413,18 +401,16 @@ static void cx25821_vidups_handler(struct work_struct *work)
return;
}
- cx25821_get_frame(dev,
- dev->channels[dev->_channel_upstream_select].
- sram_channels);
+ cx25821_get_frame(dev, dev->channels[dev->_channel_upstream_select].
+ sram_channels);
}
int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
{
struct file *myfile;
int i = 0, j = 0;
- int line_size =
- (dev->_pixel_format ==
- PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ;
+ int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ?
+ Y411_LINE_SZ : Y422_LINE_SZ;
ssize_t vfs_read_retval = 0;
char mybuf[line_size];
loff_t pos;
@@ -461,8 +447,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
for (i = 0; i < dev->_lines_count; i++) {
pos = offset;
- vfs_read_retval =
- vfs_read(myfile, mybuf, line_size, &pos);
+ vfs_read_retval = vfs_read(myfile, mybuf,
+ line_size, &pos);
if (vfs_read_retval > 0
&& vfs_read_retval == line_size
@@ -489,8 +475,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
break;
}
- dev->_file_status =
- (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+ dev->_file_status = (vfs_read_retval == line_size) ?
+ IN_PROGRESS : END_OF_FILE;
set_fs(old_fs);
myfile->f_pos = 0;
@@ -507,14 +493,12 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
dma_addr_t dma_addr;
dma_addr_t data_dma_addr;
- if (dev->_dma_virt_addr != NULL) {
+ if (dev->_dma_virt_addr != NULL)
pci_free_consistent(dev->pci, dev->upstream_riscbuf_size,
- dev->_dma_virt_addr, dev->_dma_phys_addr);
- }
+ dev->_dma_virt_addr, dev->_dma_phys_addr);
- dev->_dma_virt_addr =
- pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size,
- &dma_addr);
+ dev->_dma_virt_addr = pci_alloc_consistent(dev->pci,
+ dev->upstream_riscbuf_size, &dma_addr);
dev->_dma_virt_start_addr = dev->_dma_virt_addr;
dev->_dma_phys_start_addr = dma_addr;
dev->_dma_phys_addr = dma_addr;
@@ -528,15 +512,13 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
/* Clear memory at address */
memset(dev->_dma_virt_addr, 0, dev->_risc_size);
- if (dev->_data_buf_virt_addr != NULL) {
+ if (dev->_data_buf_virt_addr != NULL)
pci_free_consistent(dev->pci, dev->upstream_databuf_size,
- dev->_data_buf_virt_addr,
- dev->_data_buf_phys_addr);
- }
+ dev->_data_buf_virt_addr,
+ dev->_data_buf_phys_addr);
/* For Video Data buffer allocation */
- dev->_data_buf_virt_addr =
- pci_alloc_consistent(dev->pci, dev->upstream_databuf_size,
- &data_dma_addr);
+ dev->_data_buf_virt_addr = pci_alloc_consistent(dev->pci,
+ dev->upstream_databuf_size, &data_dma_addr);
dev->_data_buf_phys_addr = data_dma_addr;
dev->_data_buf_size = dev->upstream_databuf_size;
@@ -553,9 +535,8 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
return ret;
/* Create RISC programs */
- ret =
- cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl,
- dev->_lines_count);
+ ret = cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl,
+ dev->_lines_count);
if (ret < 0) {
pr_info("Failed creating Video Upstream Risc programs!\n");
goto error;
@@ -672,10 +653,9 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
vid_status = cx_read(sram_ch->int_stat);
/* Only deal with our interrupt */
- if (vid_status) {
- handled =
- cx25821_video_upstream_irq(dev, channel_num, vid_status);
- }
+ if (vid_status)
+ handled = cx25821_video_upstream_irq(dev, channel_num,
+ vid_status);
if (handled < 0)
cx25821_stop_upstream_video_ch1(dev);
@@ -747,8 +727,7 @@ int cx25821_start_video_dma_upstream(struct cx25821_dev *dev,
tmp = cx_read(sram_ch->int_msk);
cx_write(sram_ch->int_msk, tmp |= _intr_msk);
- err =
- request_irq(dev->pci->irq, cx25821_upstream_irq,
+ err = request_irq(dev->pci->irq, cx25821_upstream_irq,
IRQF_SHARED, dev->name, dev);
if (err < 0) {
pr_err("%s: can't get upstream IRQ %d\n",
@@ -807,43 +786,38 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
dev->_file_status = RESET_STATUS;
dev->_lines_count = dev->_isNTSC ? 480 : 576;
dev->_pixel_format = pixel_format;
- dev->_line_size =
- (dev->_pixel_format ==
- PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
+ dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ?
+ (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ;
- risc_buffer_size =
- dev->_isNTSC ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
+ risc_buffer_size = dev->_isNTSC ?
+ NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
if (dev->input_filename) {
str_length = strlen(dev->input_filename);
- dev->_filename = kmalloc(str_length + 1, GFP_KERNEL);
+ dev->_filename = kmemdup(dev->input_filename, str_length + 1,
+ GFP_KERNEL);
if (!dev->_filename)
goto error;
-
- memcpy(dev->_filename, dev->input_filename, str_length + 1);
} else {
str_length = strlen(dev->_defaultname);
- dev->_filename = kmalloc(str_length + 1, GFP_KERNEL);
+ dev->_filename = kmemdup(dev->_defaultname, str_length + 1,
+ GFP_KERNEL);
if (!dev->_filename)
goto error;
-
- memcpy(dev->_filename, dev->_defaultname, str_length + 1);
}
/* Default if filename is empty string */
if (strcmp(dev->input_filename, "") == 0) {
if (dev->_isNTSC) {
dev->_filename =
- (dev->_pixel_format ==
- PIXEL_FRMT_411) ? "/root/vid411.yuv" :
- "/root/vidtest.yuv";
+ (dev->_pixel_format == PIXEL_FRMT_411) ?
+ "/root/vid411.yuv" : "/root/vidtest.yuv";
} else {
dev->_filename =
- (dev->_pixel_format ==
- PIXEL_FRMT_411) ? "/root/pal411.yuv" :
- "/root/pal422.yuv";
+ (dev->_pixel_format == PIXEL_FRMT_411) ?
+ "/root/pal411.yuv" : "/root/pal422.yuv";
}
}
@@ -852,13 +826,11 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
dev->_file_status = RESET_STATUS;
dev->_lines_count = dev->_isNTSC ? 480 : 576;
dev->_pixel_format = pixel_format;
- dev->_line_size =
- (dev->_pixel_format ==
- PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
+ dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ?
+ (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
- retval =
- cx25821_sram_channel_setup_upstream(dev, sram_ch, dev->_line_size,
- 0);
+ retval = cx25821_sram_channel_setup_upstream(dev, sram_ch,
+ dev->_line_size, 0);
/* setup fifo + format */
cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format);
diff --git a/drivers/media/video/cx25821/cx25821-video.c b/drivers/media/video/cx25821/cx25821-video.c
index 4d6907cda75b..ffd8bc79c02e 100644
--- a/drivers/media/video/cx25821/cx25821-video.c
+++ b/drivers/media/video/cx25821/cx25821-video.c
@@ -118,12 +118,12 @@ void cx25821_dump_video_queue(struct cx25821_dev *dev,
if (!list_empty(&q->active)) {
list_for_each(item, &q->active)
- buf = list_entry(item, struct cx25821_buffer, vb.queue);
+ buf = list_entry(item, struct cx25821_buffer, vb.queue);
}
if (!list_empty(&q->queued)) {
list_for_each(item, &q->queued)
- buf = list_entry(item, struct cx25821_buffer, vb.queue);
+ buf = list_entry(item, struct cx25821_buffer, vb.queue);
}
}
@@ -140,8 +140,8 @@ void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
break;
}
- buf =
- list_entry(q->active.next, struct cx25821_buffer, vb.queue);
+ buf = list_entry(q->active.next, struct cx25821_buffer,
+ vb.queue);
/* count comes from the hw and it is 16bit wide --
* this trick handles wrap-arounds correctly for
@@ -318,8 +318,8 @@ int cx25821_restart_video_queue(struct cx25821_dev *dev,
struct list_head *item;
if (!list_empty(&q->active)) {
- buf =
- list_entry(q->active.next, struct cx25821_buffer, vb.queue);
+ buf = list_entry(q->active.next, struct cx25821_buffer,
+ vb.queue);
cx25821_start_video_dma(dev, q, buf, channel);
@@ -337,8 +337,8 @@ int cx25821_restart_video_queue(struct cx25821_dev *dev,
if (list_empty(&q->queued))
return 0;
- buf =
- list_entry(q->queued.next, struct cx25821_buffer, vb.queue);
+ buf = list_entry(q->queued.next, struct cx25821_buffer,
+ vb.queue);
if (NULL == prev) {
list_move_tail(&buf->vb.queue, &q->active);
@@ -375,8 +375,8 @@ void cx25821_vid_timeout(unsigned long data)
spin_lock_irqsave(&dev->slock, flags);
while (!list_empty(&q->active)) {
- buf =
- list_entry(q->active.next, struct cx25821_buffer, vb.queue);
+ buf = list_entry(q->active.next, struct cx25821_buffer,
+ vb.queue);
list_del(&buf->vb.queue);
buf->vb.state = VIDEOBUF_ERROR;
@@ -484,8 +484,7 @@ int cx25821_video_register(struct cx25821_dev *dev)
cx25821_init_controls(dev, i);
cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper,
- dev->channels[i].sram_channels->dma_ctl,
- 0x11, 0);
+ dev->channels[i].sram_channels->dma_ctl, 0x11, 0);
dev->channels[i].sram_channels = &cx25821_sram_channels[i];
dev->channels[i].video_dev = NULL;
@@ -499,15 +498,14 @@ int cx25821_video_register(struct cx25821_dev *dev)
dev->channels[i].timeout_data.dev = dev;
dev->channels[i].timeout_data.channel =
&cx25821_sram_channels[i];
- dev->channels[i].vidq.timeout.function =
- cx25821_vid_timeout;
+ dev->channels[i].vidq.timeout.function = cx25821_vid_timeout;
dev->channels[i].vidq.timeout.data =
(unsigned long)&dev->channels[i].timeout_data;
init_timer(&dev->channels[i].vidq.timeout);
/* register v4l devices */
- dev->channels[i].video_dev = cx25821_vdev_init(dev,
- dev->pci, &cx25821_video_device, "video");
+ dev->channels[i].video_dev = cx25821_vdev_init(dev, dev->pci,
+ &cx25821_video_device, "video");
err = video_register_device(dev->channels[i].video_dev,
VFL_TYPE_GRABBER, video_nr[dev->nr]);
@@ -528,7 +526,6 @@ int cx25821_video_register(struct cx25821_dev *dev)
#endif
mutex_unlock(&dev->lock);
-
return 0;
fail_unreg:
@@ -558,7 +555,7 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
struct cx25821_fh *fh = q->priv_data;
struct cx25821_dev *dev = fh->dev;
struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
+ container_of(vb, struct cx25821_buffer, vb);
int rc, init_buffer = 0;
u32 line0_offset, line1_offset;
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
@@ -617,14 +614,13 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
if (channel_opened >= 0 && channel_opened <= 7) {
if (dev->channels[channel_opened]
.use_cif_resolution) {
- if (dev->tvnorm & V4L2_STD_PAL_BG
- || dev->tvnorm & V4L2_STD_PAL_DK)
+ if (dev->tvnorm & V4L2_STD_PAL_BG ||
+ dev->tvnorm & V4L2_STD_PAL_DK)
bpl_local = 352 << 1;
else
- bpl_local =
- dev->channels[channel_opened].
- cif_width <<
- 1;
+ bpl_local = dev->channels[
+ channel_opened].
+ cif_width << 1;
}
}
}
@@ -685,7 +681,7 @@ void cx25821_buffer_release(struct videobuf_queue *q,
struct videobuf_buffer *vb)
{
struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
+ container_of(vb, struct cx25821_buffer, vb);
cx25821_free_buffer(q, buf);
}
@@ -723,7 +719,7 @@ int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
{
struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
+ container_of(vb, struct cx25821_buffer, vb);
struct cx25821_buffer *prev;
struct cx25821_fh *fh = vq->priv_data;
struct cx25821_dev *dev = fh->dev;
@@ -814,7 +810,7 @@ static int video_open(struct file *file)
for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) {
if (h->channels[i].video_dev &&
- h->channels[i].video_dev->minor == minor) {
+ h->channels[i].video_dev->minor == minor) {
dev = h;
ch_id = i;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -848,11 +844,10 @@ static int video_open(struct file *file)
v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh, NULL);
+ videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev,
+ &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
+ fh, NULL);
dprintk(1, "post videobuf_queue_init()\n");
mutex_unlock(&cx25821_devlist_mutex);
@@ -1168,8 +1163,8 @@ int cx25821_vidioc_querycap(struct file *file, void *priv,
strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
cap->version = CX25821_VERSION_CODE;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
if (UNSET != dev->tuner_type)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
@@ -1454,38 +1449,38 @@ static const struct v4l2_queryctrl no_ctl = {
static struct v4l2_queryctrl cx25821_ctls[] = {
/* --- video --- */
{
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 10000,
- .step = 1,
- .default_value = 6200,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }, {
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 10000,
- .step = 1,
- .default_value = 5000,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }, {
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 10000,
- .step = 1,
- .default_value = 5000,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }, {
- .id = V4L2_CID_HUE,
- .name = "Hue",
- .minimum = 0,
- .maximum = 10000,
- .step = 1,
- .default_value = 5000,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }
+ .id = V4L2_CID_BRIGHTNESS,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 10000,
+ .step = 1,
+ .default_value = 6200,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 10000,
+ .step = 1,
+ .default_value = 5000,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 10000,
+ .step = 1,
+ .default_value = 5000,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }, {
+ .id = V4L2_CID_HUE,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 10000,
+ .step = 1,
+ .default_value = 5000,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
};
static const int CX25821_CTLS = ARRAY_SIZE(cx25821_ctls);
@@ -1623,7 +1618,8 @@ int cx25821_vidioc_cropcap(struct file *file, void *priv,
if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- cropcap->bounds.top = cropcap->bounds.left = 0;
+ cropcap->bounds.top = 0;
+ cropcap->bounds.left = 0;
cropcap->bounds.width = 720;
cropcap->bounds.height = dev->tvnorm == V4L2_STD_PAL_BG ? 576 : 480;
cropcap->pixelaspect.numerator =
@@ -1829,8 +1825,11 @@ static long video_ioctl_set(struct file *file, unsigned int cmd,
struct downstream_user_struct *data_from_user;
int command;
int width = 720;
- int selected_channel = 0, pix_format = 0, i = 0;
- int cif_enable = 0, cif_width = 0;
+ int selected_channel = 0;
+ int pix_format = 0;
+ int i = 0;
+ int cif_enable = 0;
+ int cif_width = 0;
u32 value = 0;
data_from_user = (struct downstream_user_struct *)arg;
@@ -1895,8 +1894,8 @@ static long video_ioctl_set(struct file *file, unsigned int cmd,
}
if (selected_channel <= 7 && selected_channel >= 0) {
- dev->channels[selected_channel].
- use_cif_resolution = cif_enable;
+ dev->channels[selected_channel].use_cif_resolution =
+ cif_enable;
dev->channels[selected_channel].cif_width = width;
} else {
for (i = 0; i < VID_CHANNEL_NUM; i++) {
@@ -1932,9 +1931,9 @@ static long video_ioctl_set(struct file *file, unsigned int cmd,
static long cx25821_video_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- int ret = 0;
+ int ret = 0;
- struct cx25821_fh *fh = file->private_data;
+ struct cx25821_fh *fh = file->private_data;
/* check to see if it's the video upstream */
if (fh->channel_id == SRAM_CH09) {
diff --git a/drivers/media/video/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h
index 2d2d00932823..b9aa801b00a7 100644
--- a/drivers/media/video/cx25821/cx25821.h
+++ b/drivers/media/video/cx25821/cx25821.h
@@ -67,7 +67,7 @@
#define MAX_CAMERAS 16
/* Max number of inputs by card */
-#define MAX_CX25821_INPUT 8
+#define MAX_CX25821_INPUT 8
#define INPUT(nr) (&cx25821_boards[dev->board].input[nr])
#define RESOURCE_VIDEO0 1
#define RESOURCE_VIDEO1 2
@@ -85,7 +85,7 @@
#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */
-#define UNKNOWN_BOARD 0
+#define UNKNOWN_BOARD 0
#define CX25821_BOARD 1
/* Currently supported by the driver */
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index 005f11093642..34b96c7cfd62 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -480,7 +480,6 @@ void cx25840_audio_set_path(struct i2c_client *client)
static void set_volume(struct i2c_client *client, int volume)
{
- struct cx25840_state *state = to_state(i2c_get_clientdata(client));
int vol;
/* Convert the volume to msp3400 values (0-127) */
@@ -496,14 +495,7 @@ static void set_volume(struct i2c_client *client, int volume)
}
/* PATH1_VOLUME */
- if (is_cx2388x(state)) {
- /* for cx23885 volume doesn't work,
- * the calculation always results in
- * e4 regardless.
- */
- cx25840_write(client, 0x8d4, volume);
- } else
- cx25840_write(client, 0x8d4, 228 - (vol * 2));
+ cx25840_write(client, 0x8d4, 228 - (vol * 2));
}
static void set_balance(struct i2c_client *client, int balance)
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index cd9976408ab3..fc1ff69cffd0 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -18,6 +18,9 @@
* CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are
* Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
*
+ * CX23888 DIF support for the HVR1850
+ * Copyright (C) 2011 Steven Toth <stoth@kernellabs.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
@@ -40,6 +43,7 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <linux/delay.h>
+#include <linux/math64.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/cx25840.h>
@@ -80,6 +84,7 @@ MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
/* ----------------------------------------------------------------------- */
+static void cx23885_std_setup(struct i2c_client *client);
int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
{
@@ -498,8 +503,13 @@ static void cx23885_initialize(struct i2c_client *client)
* 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
* 572.73 MHz before post divide
*/
- cx25840_write4(client, 0x11c, 0x00e8ba26);
- cx25840_write4(client, 0x118, 0x0000040b);
+ /* HVR1850 or 50MHz xtal */
+ cx25840_write(client, 0x2, 0x71);
+ cx25840_write4(client, 0x11c, 0x01d1744c);
+ cx25840_write4(client, 0x118, 0x00000416);
+ cx25840_write4(client, 0x404, 0x0010253e);
+ cx25840_write4(client, 0x42c, 0x42600000);
+ cx25840_write4(client, 0x44c, 0x161f1000);
break;
case V4L2_IDENT_CX23887_AV:
/*
@@ -533,8 +543,18 @@ static void cx23885_initialize(struct i2c_client *client)
* 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz
* 432.0 MHz before post divide
*/
- cx25840_write4(client, 0x10c, 0x002be2c9);
- cx25840_write4(client, 0x108, 0x0000040f);
+
+ /* HVR1850 */
+ switch (state->id) {
+ case V4L2_IDENT_CX23888_AV:
+ /* 888/HVR1250 specific */
+ cx25840_write4(client, 0x10c, 0x13333333);
+ cx25840_write4(client, 0x108, 0x00000515);
+ break;
+ default:
+ cx25840_write4(client, 0x10c, 0x002be2c9);
+ cx25840_write4(client, 0x108, 0x0000040f);
+ }
/* Luma */
cx25840_write4(client, 0x414, 0x00107d12);
@@ -556,8 +576,9 @@ static void cx23885_initialize(struct i2c_client *client)
* 368.64 MHz before post divide
* 122.88 MHz / 0xa = 12.288 MHz
*/
- cx25840_write4(client, 0x114, 0x00bedfa4);
- cx25840_write4(client, 0x110, 0x000a0307);
+ /* HVR1850 or 50MHz xtal */
+ cx25840_write4(client, 0x114, 0x017dbf48);
+ cx25840_write4(client, 0x110, 0x000a030e);
break;
case V4L2_IDENT_CX23887_AV:
/*
@@ -617,7 +638,10 @@ static void cx23885_initialize(struct i2c_client *client)
finish_wait(&state->fw_wait, &wait);
destroy_workqueue(q);
- cx25840_std_setup(client);
+ /* Call the cx23885 specific std setup func, we no longer rely on
+ * the generic cx24840 func.
+ */
+ cx23885_std_setup(client);
/* (re)set input */
set_input(client, state->vid_input, state->aud_input);
@@ -631,6 +655,37 @@ static void cx23885_initialize(struct i2c_client *client)
/* Disable and clear audio interrupts - we don't use them */
cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff);
cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff);
+
+ /* CC raw enable */
+ /* - VIP 1.1 control codes - 10bit, blue field enable.
+ * - enable raw data during vertical blanking.
+ * - enable ancillary Data insertion for 656 or VIP.
+ */
+ cx25840_write4(client, 0x404, 0x0010253e);
+
+ /* CC on - Undocumented Register */
+ cx25840_write(client, 0x42f, 0x66);
+
+ /* HVR-1250 / HVR1850 DIF related */
+ /* Power everything up */
+ cx25840_write4(client, 0x130, 0x0);
+
+ /* Undocumented */
+ cx25840_write4(client, 0x478, 0x6628021F);
+
+ /* AFE_CLK_OUT_CTRL - Select the clock output source as output */
+ cx25840_write4(client, 0x144, 0x5);
+
+ /* I2C_OUT_CTL - I2S output configuration as
+ * Master, Sony, Left justified, left sample on WS=1
+ */
+ cx25840_write4(client, 0x918, 0x1a0);
+
+ /* AFE_DIAG_CTRL1 */
+ cx25840_write4(client, 0x134, 0x000a1800);
+
+ /* AFE_DIAG_CTRL3 - Inverted Polarity for Audio and Video */
+ cx25840_write4(client, 0x13c, 0x00310000);
}
/* ----------------------------------------------------------------------- */
@@ -945,9 +1000,14 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
vid_input <= CX25840_COMPOSITE8);
u8 is_component = (vid_input & CX25840_COMPONENT_ON) ==
CX25840_COMPONENT_ON;
+ u8 is_dif = (vid_input & CX25840_DIF_ON) ==
+ CX25840_DIF_ON;
+ u8 is_svideo = (vid_input & CX25840_SVIDEO_ON) ==
+ CX25840_SVIDEO_ON;
int luma = vid_input & 0xf0;
int chroma = vid_input & 0xf00;
u8 reg;
+ u32 val;
v4l_dbg(1, cx25840_debug, client,
"decoder set video input %d, audio input %d\n",
@@ -1012,6 +1072,66 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
else
cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
+ if (is_cx2388x(state)) {
+
+ /* Enable or disable the DIF for tuner use */
+ if (is_dif) {
+ cx25840_and_or(client, 0x102, ~0x80, 0x80);
+
+ /* Set of defaults for NTSC and PAL */
+ cx25840_write4(client, 0x31c, 0xc2262600);
+ cx25840_write4(client, 0x320, 0xc2262600);
+
+ /* 18271 IF - Nobody else yet uses a different
+ * tuner with the DIF, so these are reasonable
+ * assumptions (HVR1250 and HVR1850 specific).
+ */
+ cx25840_write4(client, 0x318, 0xda262600);
+ cx25840_write4(client, 0x33c, 0x2a24c800);
+ cx25840_write4(client, 0x104, 0x0704dd00);
+ } else {
+ cx25840_write4(client, 0x300, 0x015c28f5);
+
+ cx25840_and_or(client, 0x102, ~0x80, 0);
+ cx25840_write4(client, 0x340, 0xdf7df83);
+ cx25840_write4(client, 0x104, 0x0704dd80);
+ cx25840_write4(client, 0x314, 0x22400600);
+ cx25840_write4(client, 0x318, 0x40002600);
+ cx25840_write4(client, 0x324, 0x40002600);
+ cx25840_write4(client, 0x32c, 0x0250e620);
+ cx25840_write4(client, 0x39c, 0x01FF0B00);
+
+ cx25840_write4(client, 0x410, 0xffff0dbf);
+ cx25840_write4(client, 0x414, 0x00137d03);
+ cx25840_write4(client, 0x418, 0x01008080);
+ cx25840_write4(client, 0x41c, 0x00000000);
+ cx25840_write4(client, 0x420, 0x001c3e0f);
+ cx25840_write4(client, 0x42c, 0x42600000);
+ cx25840_write4(client, 0x430, 0x0000039b);
+ cx25840_write4(client, 0x438, 0x00000000);
+
+ cx25840_write4(client, 0x440, 0xF8E3E824);
+ cx25840_write4(client, 0x444, 0x401040dc);
+ cx25840_write4(client, 0x448, 0xcd3f02a0);
+ cx25840_write4(client, 0x44c, 0x161f1000);
+ cx25840_write4(client, 0x450, 0x00000802);
+
+ cx25840_write4(client, 0x91c, 0x01000000);
+ cx25840_write4(client, 0x8e0, 0x03063870);
+ cx25840_write4(client, 0x8d4, 0x7FFF0024);
+ cx25840_write4(client, 0x8d0, 0x00063073);
+
+ cx25840_write4(client, 0x8c8, 0x00010000);
+ cx25840_write4(client, 0x8cc, 0x00080023);
+
+ /* DIF BYPASS */
+ cx25840_write4(client, 0x33c, 0x2a04c800);
+ }
+
+ /* Reset the DIF */
+ cx25840_write4(client, 0x398, 0);
+ }
+
if (!is_cx2388x(state) && !is_cx231xx(state)) {
/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
@@ -1036,6 +1156,33 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
cx25840_and_or(client, 0x102, ~0x2, 0);
}
}
+
+ /* cx23885 / SVIDEO */
+ if (is_cx2388x(state) && is_svideo) {
+#define AFE_CTRL (0x104)
+#define MODE_CTRL (0x400)
+ cx25840_and_or(client, 0x102, ~0x2, 0x2);
+
+ val = cx25840_read4(client, MODE_CTRL);
+ val &= 0xFFFFF9FF;
+
+ /* YC */
+ val |= 0x00000200;
+ val &= ~0x2000;
+ cx25840_write4(client, MODE_CTRL, val);
+
+ val = cx25840_read4(client, AFE_CTRL);
+
+ /* Chroma in select */
+ val |= 0x00001000;
+ val &= 0xfffffe7f;
+ /* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8).
+ * This sets them to use video rather than audio.
+ * Only one of the two will be in use.
+ */
+ cx25840_write4(client, AFE_CTRL, val);
+ } else
+ cx25840_and_or(client, 0x102, ~0x2, 0);
}
state->vid_input = vid_input;
@@ -1086,6 +1233,23 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
cx25840_write4(client, 0x8d0, 0x1f063870);
}
+ if (is_cx2388x(state)) {
+ /* HVR1850 */
+ /* AUD_IO_CTRL - I2S Input, Parallel1*/
+ /* - Channel 1 src - Parallel1 (Merlin out) */
+ /* - Channel 2 src - Parallel2 (Merlin out) */
+ /* - Channel 3 src - Parallel3 (Merlin AC97 out) */
+ /* - I2S source and dir - Merlin, output */
+ cx25840_write4(client, 0x124, 0x100);
+
+ if (!is_dif) {
+ /* Stop microcontroller if we don't need it
+ * to avoid audio popping on svideo/composite use.
+ */
+ cx25840_and_or(client, 0x803, ~0x10, 0x00);
+ }
+ }
+
return 0;
}
@@ -1134,7 +1298,10 @@ static int set_v4lstd(struct i2c_client *client)
}
cx25840_and_or(client, 0x400, ~0xf, fmt);
cx25840_and_or(client, 0x403, ~0x3, pal_m);
- cx25840_std_setup(client);
+ if (is_cx2388x(state))
+ cx23885_std_setup(client);
+ else
+ cx25840_std_setup(client);
if (!is_cx2583x(state))
input_change(client);
return 0;
@@ -1539,6 +1706,56 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
+/* Query the current detected video format */
+static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ v4l2_std_id stds[] = {
+ /* 0000 */ V4L2_STD_UNKNOWN,
+
+ /* 0001 */ V4L2_STD_NTSC_M,
+ /* 0010 */ V4L2_STD_NTSC_M_JP,
+ /* 0011 */ V4L2_STD_NTSC_443,
+ /* 0100 */ V4L2_STD_PAL,
+ /* 0101 */ V4L2_STD_PAL_M,
+ /* 0110 */ V4L2_STD_PAL_N,
+ /* 0111 */ V4L2_STD_PAL_Nc,
+ /* 1000 */ V4L2_STD_PAL_60,
+
+ /* 1001 */ V4L2_STD_UNKNOWN,
+ /* 1010 */ V4L2_STD_UNKNOWN,
+ /* 1001 */ V4L2_STD_UNKNOWN,
+ /* 1010 */ V4L2_STD_UNKNOWN,
+ /* 1011 */ V4L2_STD_UNKNOWN,
+ /* 1110 */ V4L2_STD_UNKNOWN,
+ /* 1111 */ V4L2_STD_UNKNOWN
+ };
+
+ u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf;
+ *std = stds[ fmt ];
+
+ v4l_dbg(1, cx25840_debug, client, "g_std fmt = %x, v4l2_std_id = 0x%x\n",
+ fmt, (unsigned int)stds[ fmt ]);
+
+ return 0;
+}
+
+static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ /* A limited function that checks for signal status and returns
+ * the state.
+ */
+
+ /* Check for status of Horizontal lock (SRC lock isn't reliable) */
+ if ((cx25840_read4(client, 0x40c) & 0x00010000) == 0)
+ *status |= V4L2_IN_ST_NO_SIGNAL;
+
+ return 0;
+}
+
static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct cx25840_state *state = to_state(sd);
@@ -1565,6 +1782,9 @@ static int cx25840_s_video_routing(struct v4l2_subdev *sd,
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ if (is_cx2388x(state))
+ cx23885_std_setup(client);
+
return set_input(client, input, state->aud_input);
}
@@ -1574,6 +1794,8 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ if (is_cx2388x(state))
+ cx23885_std_setup(client);
return set_input(client, state->vid_input, input);
}
@@ -1786,6 +2008,3007 @@ static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status,
/* ----------------------------------------------------------------------- */
+#define DIF_PLL_FREQ_WORD (0x300)
+#define DIF_BPF_COEFF01 (0x348)
+#define DIF_BPF_COEFF23 (0x34c)
+#define DIF_BPF_COEFF45 (0x350)
+#define DIF_BPF_COEFF67 (0x354)
+#define DIF_BPF_COEFF89 (0x358)
+#define DIF_BPF_COEFF1011 (0x35c)
+#define DIF_BPF_COEFF1213 (0x360)
+#define DIF_BPF_COEFF1415 (0x364)
+#define DIF_BPF_COEFF1617 (0x368)
+#define DIF_BPF_COEFF1819 (0x36c)
+#define DIF_BPF_COEFF2021 (0x370)
+#define DIF_BPF_COEFF2223 (0x374)
+#define DIF_BPF_COEFF2425 (0x378)
+#define DIF_BPF_COEFF2627 (0x37c)
+#define DIF_BPF_COEFF2829 (0x380)
+#define DIF_BPF_COEFF3031 (0x384)
+#define DIF_BPF_COEFF3233 (0x388)
+#define DIF_BPF_COEFF3435 (0x38c)
+#define DIF_BPF_COEFF36 (0x390)
+
+void cx23885_dif_setup(struct i2c_client *client, u32 ifHz)
+{
+ u64 pll_freq;
+ u32 pll_freq_word;
+
+ v4l_dbg(1, cx25840_debug, client, "%s(%d)\n", __func__, ifHz);
+
+ /* Assuming TV */
+ /* Calculate the PLL frequency word based on the adjusted ifHz */
+ pll_freq = div_u64((u64)ifHz * 268435456, 50000000);
+ pll_freq_word = (u32)pll_freq;
+
+ cx25840_write4(client, DIF_PLL_FREQ_WORD, pll_freq_word);
+
+ /* Round down to the nearest 100KHz */
+ ifHz = (ifHz / 100000) * 100000;
+
+ if (ifHz < 3000000)
+ ifHz = 3000000;
+
+ if (ifHz > 16000000)
+ ifHz = 16000000;
+
+ v4l_dbg(1, cx25840_debug, client, "%s(%d) again\n", __func__, ifHz);
+
+ switch (ifHz) {
+ case 3000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0024);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x001bfff8);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff50);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed8fe68);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe34);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfebaffc7);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d031f);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x04f0065d);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x07010688);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x04c901d6);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f9d3);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f342);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f337);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf64efb22);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105070f);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x0c460fce);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 3100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00220032);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00370026);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff91);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0efe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fdcc);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe0afedb);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440224);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0434060c);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738074e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x06090361);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99fb39);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef3b6);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21af2a5);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf573fa33);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034067d);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bfb0fb9);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 3200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000e);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00200038);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x004c004f);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x002fffdf);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff5cfeb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dfd92);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7ffe03);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36010a);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x03410575);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x072607d2);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x071804d5);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134fcb7);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff451);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223f22e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4a7f94b);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xff6405e8);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bae0fa4);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 3300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00000008);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0036);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0056006d);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00670030);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffbdff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46fd8d);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd25fd4f);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35ffe0);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0224049f);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9080e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x07ef0627);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9fe45);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f513);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250f1d2);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3ecf869);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930552);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b5f0f8f);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 3400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0001);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x000f002c);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0054007d);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0093007c);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0024ff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6fdbb);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd03fcca);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51feb9);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x00eb0392);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270802);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08880750);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x044dffdb);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf5f8);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0f193);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf342f78f);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc404b9);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b0e0f78);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 3500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff9);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0002001b);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0046007d);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad00ba);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00870000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe1a);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1bfc7e);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fda4);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xffa5025c);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x054507ad);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08dd0847);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80172);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef6ff);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313f170);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2abf6bd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6041f);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x0abc0f61);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 3600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff3);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff50006);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x002f006c);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00b200e3);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00dc007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9fea0);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd6bfc71);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fcb1);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe65010b);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x042d0713);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ec0906);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020302);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff823);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7f16a);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf228f5f5);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2a0384);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a670f4a);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 3700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7ffef);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9fff1);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0010004d);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00a100f2);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x011a00f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053ff44);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdedfca2);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fbef);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd39ffae);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x02ea0638);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08b50987);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230483);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f960);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45bf180);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1b8f537);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb6102e7);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a110f32);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 3800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffdd);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00024);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x007c00e5);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x013a014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e6fff8);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe98fd0f);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fb67);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc32fe54);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x01880525);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x083909c7);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x091505ee);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7fab3);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52df1b4);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf15df484);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9b0249);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x09ba0f19);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 3900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff0);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffcf);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1fff6);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x004800be);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x01390184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x016300ac);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xff5efdb1);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb23);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb5cfd0d);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x001703e4);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x077b09c4);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d2073c);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251fc18);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61cf203);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf118f3dc);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d801aa);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x09600eff);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 4000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffefff4);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffc8);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffca);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x000b0082);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x01170198);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10152);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0030fe7b);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb24);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfac3fbe9);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5027f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x0683097f);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a560867);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2fd89);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723f26f);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0e8f341);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919010a);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x09060ee5);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 4100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fffb);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8ffca);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffa4);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffcd0036);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d70184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f601dc);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ffff60);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb6d);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6efaf5);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd410103);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x055708f9);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e0969);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543ff02);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842f2f5);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cef2b2);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85e006b);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x08aa0ecb);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 4200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00050003);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff3ffd3);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaff8b);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ffe5);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0080014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe023f);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ba0050);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fbf8);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa62fa3b);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9ff7e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x04010836);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa90a3d);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f007f);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf975f395);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cbf231);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ffcb);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x084c0eaf);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 4300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000a);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0000ffe4);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff81);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff96);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x001c00f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70271);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0254013b);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fcbd);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa9ff9c5);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbfdfe);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x028c073b);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a750adf);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e101fa);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab8f44e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0ddf1be);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ff2b);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x07ed0e94);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 4400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000f);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x000efff8);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff87);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff54);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffb5007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01860270);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c00210);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fdb2);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb22f997);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2fc90);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x0102060f);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a050b4c);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902036e);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0af51e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf106f15a);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64efe8b);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x078d0e77);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 4500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0019000e);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff9e);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff25);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff560000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112023b);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f702c0);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfec8);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbe5f9b3);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947fb41);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xff7004b9);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a0b81);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a0004d8);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd65f603);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf144f104);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aafdec);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x072b0e5a);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 4600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00060012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00200022);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ffc1);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff09ff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x008601d7);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f50340);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fff0);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcddfa19);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa1e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfde30343);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x08790b7f);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50631);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec7f6fc);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf198f0bd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50dfd4e);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x06c90e3d);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 4700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00220030);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffed);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff87ff15);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed6ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xffed014c);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b90386);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110119);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfdfefac4);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6f92f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc6701b7);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x07670b44);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0776);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x002df807);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf200f086);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477fcb1);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x06650e1e);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 4800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0009);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0038);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x003f001b);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffbcff36);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec2feb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff5600a5);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0248038d);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00232);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xff39fbab);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4f87f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb060020);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x062a0ad2);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf908a3);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0192f922);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf27df05e);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8fc14);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x06000e00);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 4900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0002);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00160037);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00510046);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xfff9ff6d);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed0fe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefff0);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x01aa0356);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413032b);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x007ffcc5);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cf812);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9cefe87);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c90a2c);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4309b4);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f3fa4a);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf30ef046);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361fb7a);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x059b0de0);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 5000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x000a002d);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00570067);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0037ffb5);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfefffe68);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62ff3d);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ec02e3);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x043503f6);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x01befe05);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa27f7ee);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8c6fcf8);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x034c0954);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0aa4);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x044cfb7e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3b1f03f);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2fae1);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x05340dc0);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 5100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff4);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfffd001e);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0051007b);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x006e0006);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff48fe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfe9a);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x001d023e);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130488);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x02e6ff5b);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1ef812);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7f7fb7f);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bc084e);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430b72);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x059afcba);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf467f046);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cfa4a);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x04cd0da0);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 5200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffef);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff00009);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x003f007f);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00980056);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffa5feb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe15);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xff4b0170);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b004d7);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x03e800b9);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc48f87f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf768fa23);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022071f);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90c1b);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x06dafdfd);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf52df05e);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef9b5);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x04640d7f);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 5300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6fff3);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00250072);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00af009c);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x000cff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13fdb8);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe870089);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104e1);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x04b8020f);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd98f92f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf71df8f0);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe8805ce);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0c9c);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0808ff44);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf603f086);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af922);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x03fb0d5e);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 5400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffef);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe0);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00050056);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00b000d1);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0071ff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53fd8c);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfddfff99);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104a3);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x054a034d);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xff01fa1e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf717f7ed);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf50461);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50cf4);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0921008d);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf6e7f0bd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff891);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x03920d3b);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 5500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffffff3);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffd1);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5002f);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x009c00ed);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00cb0000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfebafd94);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd61feb0);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d0422);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x05970464);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0074fb41);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf759f721);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb7502de);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000d21);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a2201d4);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7d9f104);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf804);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x03280d19);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 5600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fffa);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3ffc9);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffc90002);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x007500ef);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x010e007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3dfdcf);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd16fddd);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440365);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x059b0548);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3fc90);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7dff691);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0f014d);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020d23);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0318);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8d7f15a);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f779);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x02bd0cf6);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 5700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00060001);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffecffc9);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffd4);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x004000d5);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x013600f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd3fe39);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd04fd31);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff360277);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x055605ef);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x033efdfe);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8a5f642);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbffb6);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10cfb);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50456);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9dff1be);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f6f2);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x02520cd2);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 5800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00080009);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff8ffd2);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffac);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x000200a3);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x013c014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x006dfec9);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2bfcb7);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe350165);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x04cb0651);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477ff7e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9a5f635);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1fe20);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0ca8);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c81058b);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfaf0f231);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f66d);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x01e60cae);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 5900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000e);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0005ffe1);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffacff90);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5005f);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x01210184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fcff72);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd8afc77);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51003f);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x04020669);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830103);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfad7f66b);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8fc93);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430c2b);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d06b5);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfc08f2b2);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af5ec);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x017b0c89);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 6000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0012fff5);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaff82);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff8e000f);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e80198);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750028);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe18fc75);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99ff15);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x03050636);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0656027f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc32f6e2);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614fb17);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20b87);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d7707d2);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfd26f341);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf56f);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x010f0c64);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 6100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00050012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001c000b);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff84);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ffbe);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00960184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd00da);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeccfcb2);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fdf9);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x01e005bc);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e703e4);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfdabf798);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f9b3);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510abd);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf08df);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfe48f3dc);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f4f6);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x00a20c3e);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 6200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0002000f);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0021001f);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff97);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff74);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0034014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa0179);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xff97fd2a);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fcfa);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x00a304fe);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310525);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xff37f886);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf86e);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c709d0);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de209db);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xff6df484);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf481);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0x00360c18);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 6300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe000a);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0021002f);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ffb8);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff3b);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffcc00f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa01fa);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0069fdd4);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fc26);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xff5d0407);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310638);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x00c9f9a8);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf74e);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xff3908c3);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de20ac3);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0093f537);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf410);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xffca0bf2);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 6400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb0003);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001c0037);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x002fffe2);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ff17);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff6a007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd0251);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0134fea5);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb8b);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe2002e0);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e70713);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x0255faf5);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f658);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0799);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf0b96);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x01b8f5f5);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f3a3);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xff5e0bca);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 6500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00120037);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00460010);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff8eff0f);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff180000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750276);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x01e8ff8d);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb31);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcfb0198);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x065607ad);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x03cefc64);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614f592);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0656);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d770c52);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x02daf6bd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf33b);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfef10ba3);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 6600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff5);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0005002f);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0054003c);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5ff22);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedfff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fc0267);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0276007e);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb1c);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbfe003e);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830802);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x0529fdec);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8f4fe);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd04ff);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d0cf6);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x03f8f78f);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af2d7);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe850b7b);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 6700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff80020);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00560060);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0002ff4e);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec4ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x006d0225);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02d50166);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb4e);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb35fee1);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477080e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x065bff82);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1f4a0);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610397);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c810d80);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0510f869);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f278);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe1a0b52);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 6800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffaffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffec000c);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0078);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0040ff8e);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecafeb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd301b6);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fc0235);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fbc5);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaaafd90);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x033e07d2);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x075b011b);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbf47a);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f0224);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50def);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0621f94b);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f21e);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfdae0b29);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 6900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffef);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3fff6);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0037007f);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0075ffdc);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef2fe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3d0122);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02ea02dd);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fc79);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa65fc5d);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3074e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x082102ad);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0ff48c);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe00a9);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0e43);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0729fa33);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f1c9);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfd430b00);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 7000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0001fff3);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe2);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x001b0076);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x009c002d);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff35fe68);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfeba0076);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x029f0352);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfd60);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa69fb53);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x00740688);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08a7042d);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb75f4d6);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600ff2d);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a220e7a);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0827fb22);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf17a);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfcd80ad6);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 7100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff9);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffd2);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb005e);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00b0007a);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8ffe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53ffc1);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0221038c);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fe6e);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfab6fa80);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xff010587);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e90590);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf5f556);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfdb3);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x09210e95);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0919fc15);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff12f);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc6e0aab);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 7200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00070000);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6ffc9);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0039);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00af00b8);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfff4feb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x01790388);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311ff92);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb48f9ed);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd980453);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e306cd);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe88f60a);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fc40);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x08080e93);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x09fdfd0c);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af0ea);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc050a81);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 7300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00080008);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff0ffc9);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1000d);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x009800e2);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x005bff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe74);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x00b50345);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000bc);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc18f9a1);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc4802f9);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x089807dc);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022f6f0);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fada);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x06da0e74);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ad3fe06);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef0ab);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb9c0a55);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 7400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000e);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfffdffd0);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffdf);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x006e00f2);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00b8ff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfdf8);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xffe302c8);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x041301dc);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd1af99e);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1e0183);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x080908b5);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bcf801);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf985);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x059a0e38);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b99ff03);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cf071);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb330a2a);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 7500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00070011);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x000affdf);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffa9ffb5);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x003700e6);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x01010000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62fda8);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xff140219);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x043502e1);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe42f9e6);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa270000);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x073a0953);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x034cf939);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a4f845);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x044c0de1);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c4f0000);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2f03c);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfacc09fe);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 7600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00040012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0016fff3);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffafff95);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xfff900c0);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0130007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefd89);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe560146);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x041303bc);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xff81fa76);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cfe7d);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x063209b1);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c9fa93);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf71e);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f30d6e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cf200fd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361f00e);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa6509d1);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 7700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00010010);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0008);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ff84);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffbc0084);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x013e00f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff56fd9f);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdb8005c);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00460);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x00c7fb45);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4fd07);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x04fa09ce);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x062afc07);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407f614);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x01920ce0);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d8301fa);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8efe5);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa0009a4);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 7800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd000b);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001d);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff82);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff870039);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x012a014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xffedfde7);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd47ff6b);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104c6);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0202fc4c);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6fbad);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x039909a7);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0767fd8e);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482f52b);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x002d0c39);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e0002f4);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477efc2);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf99b0977);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 7900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa0004);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0020002d);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff91);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ffe8);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f70184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0086fe5c);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0bfe85);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104e5);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0323fd7d);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa79);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x021d093f);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0879ff22);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bf465);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec70b79);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e6803eb);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50defa5);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf937094a);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 8000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffd);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00190036);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x001bffaf);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff99);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00aa0198);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112fef3);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd09fdb9);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04be);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x041bfecc);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947f978);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x00900897);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a00b9);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f3c5);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd650aa3);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ebc04de);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aaef8e);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf8d5091c);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 8100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff6);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x000e0038);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ffd7);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff56);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x004b0184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0186ffa1);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd40fd16);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440452);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x04de0029);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2f8b2);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfefe07b5);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a05024d);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef34d);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0a09b8);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0efa05cd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64eef7d);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf87308ed);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 8200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00000031);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0005);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff27);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffe4014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70057);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdacfca6);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3603a7);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x05610184);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbf82e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd74069f);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a7503d6);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff2ff);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab808b9);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f2306b5);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ef72);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf81308bf);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 8300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff30022);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00560032);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8000f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe0106);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe46fc71);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3502c7);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x059e02ce);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9f7f2);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfbff055b);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa9054c);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f2db);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf97507aa);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f350797);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ef6d);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7b40890);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 8400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8000f);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00540058);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffcdff14);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff29007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f6019e);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xff01fc7c);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5101bf);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x059203f6);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd41f7fe);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfaa903f3);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e06a9);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf2e2);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842068b);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f320871);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85eef6e);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7560860);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 8500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fff2);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1fff9);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00460073);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x000bff34);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee90000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10215);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xffd0fcc5);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99009d);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x053d04f1);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5f853);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf97d0270);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a5607e4);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef314);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723055f);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f180943);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919ef75);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6fa0830);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 8600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff8);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe4);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x002f007f);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0048ff6b);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec7ff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0163025f);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x00a2fd47);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff73);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x04a405b2);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0017f8ed);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf88500dc);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d208f9);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff370);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61c0429);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ee80a0b);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d8ef82);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6a00800);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 8700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0007ffff);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffd4);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0010007a);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x007cffb2);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec6ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e60277);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0168fdf9);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fe50);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x03ce0631);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0188f9c8);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7c7ff43);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x091509e3);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f3f6);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52d02ea);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ea30ac9);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9bef95);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf64607d0);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 8800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00090007);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9ffca);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00065);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00a10003);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee6feb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053025b);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0213fed0);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fd46);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x02c70668);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x02eafadb);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf74bfdae);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230a9c);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f4a3);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45b01a6);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e480b7c);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb61efae);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf5ef079f);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 8900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000d);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff5ffc8);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10043);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00b20053);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff24fe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9020c);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0295ffbb);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fc64);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x019b0654);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x042dfc1c);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf714fc2a);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020b21);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f575);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7005e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0dd80c24);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2aefcd);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf599076e);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 9000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00060011);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0002ffcf);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffba0018);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad009a);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff79fe68);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff260192);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e500ab);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fbb6);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x005b05f7);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545fd81);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf723fabf);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80b70);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f669);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313ff15);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d550cbf);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6eff2);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544073d);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 9100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00030012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x000fffdd);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffea);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x009300cf);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdcfe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea600f7);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fd0190);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb46);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xff150554);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0627fefd);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf778f978);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x044d0b87);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f77d);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0fdcf);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbe0d4e);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc4f01d);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2070b);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 9200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00000010);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001afff0);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffbf);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x006700ed);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043feb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe460047);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02db0258);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb1b);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddc0473);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c90082);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf811f85e);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c90b66);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff8ad);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250fc8d);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c140dcf);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe93f04d);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a106d9);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 9300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc000c);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00200006);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff9c);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x002f00ef);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a4ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dff92);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x028102f7);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb37);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbf035e);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x07260202);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e8f778);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x01340b0d);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f9f4);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223fb51);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b590e42);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xff64f083);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf45206a7);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 9400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90005);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001a);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff86);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xfff000d7);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2ff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fee5);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f60362);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb99);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbcc0222);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x07380370);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f7f6cc);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xff990a7e);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902fb50);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21afa1f);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8d0ea6);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034f0bf);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4050675);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 9500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffe);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001e002b);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff81);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffb400a5);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe50);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x01460390);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfc3a);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb1000ce);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x070104bf);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb37f65f);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe0009bc);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00fcbb);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f8f8);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b20efc);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105f101);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3ba0642);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 9600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff7);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00150036);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff8c);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff810061);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x013d007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe71fddf);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x007c0380);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fd13);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa94ff70);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x068005e2);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9bf633);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc7308ca);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5fe30);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf274f7e0);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c90f43);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d4f147);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371060f);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 9700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fff1);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00090038);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffa7);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff5e0012);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x013200f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee3fd9b);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaa0331);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fe15);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa60fe18);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bd06d1);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1bf64a);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafa07ae);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7effab);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d5f6d7);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d30f7a);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a3f194);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf32905dc);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 9800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfffb0032);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x003fffcd);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effc1);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6efd8a);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfedd02aa);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0ff34);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa74fcd7);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bf0781);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaaf6a3);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99e066b);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90128);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf359f5e1);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d20fa2);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0370f1e5);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e405a8);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 9900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffef0024);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0051fffa);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff54ff77);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00be0184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0006fdad);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe2701f3);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413005e);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad1fbba);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x039007ee);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x013bf73d);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868050a);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4302a1);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fdf4fe);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c70fba);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x043bf23c);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a10575);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 10000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fff1);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe50011);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00570027);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff70ff3c);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00620198);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x009efe01);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95011a);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350183);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb71fad0);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x023c0812);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c3f811);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75e0390);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0411);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c1f432);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b30fc1);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0503f297);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2610541);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 10100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0006fff7);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffdffffc);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00510050);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff9dff18);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffc0184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0128fe80);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32002e);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130292);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4dfa21);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d107ee);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x0435f91c);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6850205);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430573);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a1f37d);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x03990fba);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c7f2f8);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222050d);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 10200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffe);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffdfffe7);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x003f006e);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffd6ff0f);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0197ff1f);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd05ff3e);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0037c);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd59f9b7);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5d0781);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x0585fa56);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4006f);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf906c4);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69df2e0);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x02790fa2);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0688f35d);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e604d8);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 10300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00090005);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4ffd6);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0025007e);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0014ff20);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3c00f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e1ffd0);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd12fe5c);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110433);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88f996);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf106d1);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aafbb7);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57efed8);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e07ff);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b0f25e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x01560f7a);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0745f3c7);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1ac04a4);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 10400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000c);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffedffcb);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0005007d);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0050ff4c);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ff0086);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd58fd97);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104ad);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xffcaf9c0);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc9905e2);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x079afd35);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf555fd46);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50920);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d9f1f6);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x00310f43);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fdf435);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174046f);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 10500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00050011);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfffaffc8);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5006b);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0082ff8c);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f00130);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd2fcfc);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04e3);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x010efa32);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb6404bf);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x084efec5);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569fbc2);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000a23);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa15f1ab);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0b0efc);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b0f4a7);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13f043a);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 10600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00020012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0007ffcd);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9004c);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00a4ffd9);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3ff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b401c1);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe76fc97);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404d2);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0245fae8);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5f0370);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1005f);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bcfa52);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020b04);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb60f17b);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde70ea6);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x095df51e);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10c0405);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 10700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0011);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0014ffdb);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40023);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2002a);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedbff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150022d);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xff38fc6f);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36047b);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x035efbda);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9940202);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ee01f5);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf649f8fe);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10bc2);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb6f169);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc60e42);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a04f599);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0db03d0);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 10800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb000d);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001dffed);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffaafff5);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00aa0077);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13feb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x00ce026b);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x000afc85);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3503e3);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x044cfcfb);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90c0082);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5037f);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf710f7cc);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0c59);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe16f173);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaa0dcf);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa5f617);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0ad039b);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 10900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90006);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00210003);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffc8);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x008e00b6);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff63fe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x003a0275);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x00dafcda);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd510313);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0501fe40);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cbfefd);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x087604f0);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80af6c2);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430cc8);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7af19a);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa940d4e);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3ff699);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0810365);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 11000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffff);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00210018);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffa3);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x006000e1);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc4fe68);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0024b);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x019afd66);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc990216);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0575ff99);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4fd81);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d40640);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf932f5e6);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20d0d);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x00dff1de);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9860cbf);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd1f71e);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058032f);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 11100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff8);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001b0029);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff8a);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x002600f2);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x002cfe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0f01f0);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x023bfe20);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc1700fa);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a200f7);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf927fc1c);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f40765);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa82f53b);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510d27);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0243f23d);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8810c24);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5cf7a7);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf03102fa);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 11200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00110035);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff81);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffe700e7);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x008ffeb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94016d);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b0fefb);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3ffd1);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x05850249);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c1fadb);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x05de0858);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf2f4c4);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c70d17);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a0f2b8);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7870b7c);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdff833);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00d02c4);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 11300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00040038);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ff88);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffac00c2);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e2ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe3900cb);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f1ffe9);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3feaa);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x05210381);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9cf9c8);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x04990912);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7af484);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xff390cdb);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f4f34d);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69a0ac9);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5af8c1);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xefec028e);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 11400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0000ffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff60033);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x002fff9f);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff7b0087);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x011eff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe080018);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f900d8);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fd96);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x04790490);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbadf8ed);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x032f098e);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xff10f47d);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0c75);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x063cf3fc);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5ba0a0b);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dccf952);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcd0258);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 11500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff1);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffea0026);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0046ffc3);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff5a003c);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04ff63);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c801b8);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fca6);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397056a);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcecf853);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x01ad09c9);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x00acf4ad);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0be7);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0773f4c2);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e90943);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35f9e6);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb10221);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 11600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff6);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe20014);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0054ffee);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effeb);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2efebb);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260027a);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fbe6);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x02870605);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4af7fe);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x001d09c1);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0243f515);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd0b32);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0897f59e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4280871);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e95fa7c);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef9701eb);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 11700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffd);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffff);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0056001d);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff57ff9c);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x011300f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe82fe2e);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ca0310);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb62);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155065a);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xffbaf7f2);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8c0977);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x03cef5b2);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610a58);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a5f68f);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3790797);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eebfb14);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef8001b5);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 11800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00080004);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe9);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0047);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff75ff58);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef9fdc8);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111036f);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb21);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x00120665);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x012df82e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd0708ec);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542f682);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f095c);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9af792);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2db06b5);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f38fbad);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6c017e);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 11900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000b);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe7ffd8);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00370068);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffa4ff28);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00790184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87fd91);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x00430392);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb26);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfece0626);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294f8b2);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb990825);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0698f77f);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe0842);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b73f8a7);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf25105cd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7bfc48);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5a0148);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 12000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00050010);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff2ffcc);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x001b007b);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffdfff10);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00140198);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0020fd8e);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xff710375);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb73);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9a059f);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e0f978);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4e0726);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c8f8a7);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600070c);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2ff9c9);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1db04de);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4fce5);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4b0111);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 12100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00010012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffffffc8);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb007e);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x001dff14);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffad0184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b7fdbe);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9031b);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fc01);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc8504d6);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0504fa79);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf93005f6);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x08caf9f2);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52b05c0);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccbfaf9);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf17903eb);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3fd83);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3f00db);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 12200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe0011);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x000cffcc);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0071);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0058ff32);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4f014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x013cfe1f);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfb028a);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fcc9);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9d03d6);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f4fbad);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848049d);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0999fb5b);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf4820461);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d46fc32);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12d02f4);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x1007fe21);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3600a4);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 12300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0017ffd9);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffc10055);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0088ff68);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0400f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a6fea7);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7501cc);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fdc0);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaef02a8);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a7fd07);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79d0326);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a31fcda);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf40702f3);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9ffd72);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f601fa);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x1021fec0);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2f006d);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 12400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80007);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001fffeb);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffaf002d);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00a8ffb0);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e9ff4c);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2000ee);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fed8);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82015c);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0715fe7d);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7340198);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8dfe69);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bd017c);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd5feb8);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d500fd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x1031ff60);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2b0037);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 12500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff70000);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00220000);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffa90000);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00b30000);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec20000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x02000000);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd030000);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350000);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa5e0000);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x073b0000);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7110000);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aac0000);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a40000);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de70000);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0c90000);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x10360000);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef290000);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 12600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff9);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001f0015);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffd3);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00a80050);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3ff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e900b4);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd20ff12);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130128);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82fea4);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x07150183);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf734fe68);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8d0197);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdfe84);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd50148);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d5ff03);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x103100a0);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2bffc9);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 12700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00170027);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ffab);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00880098);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff04ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a60159);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd75fe34);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00240);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaeffd58);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a702f9);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79dfcda);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a310326);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fd0d);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9f028e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f6fe06);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x10210140);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2fff93);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 12800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffef);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x000c0034);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff8f);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x005800ce);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4ffeb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x013c01e1);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfbfd76);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110337);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9dfc2a);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f40453);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848fb63);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x099904a5);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fb9f);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d4603ce);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12dfd0c);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x100701df);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef36ff5c);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 12900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0001ffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffff0038);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff82);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x001d00ec);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffadfe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b70242);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9fce5);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x024103ff);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc85fb2a);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x05040587);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf930fa0a);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x08ca060e);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfa40);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccb0507);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf179fc15);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3027d);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3fff25);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 13000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff0);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff20034);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x001bff85);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffdf00f0);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0014fe68);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x00200272);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xff71fc8b);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d048d);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9afa61);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e00688);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4ef8da);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c80759);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f8f4);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2f0637);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1dbfb22);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4031b);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4bfeef);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 13100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff5);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe70028);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ff98);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffa400d8);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0079fe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87026f);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0043fc6e);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404da);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfecef9da);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294074e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb99f7db);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x06980881);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef7be);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b730759);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf251fa33);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7b03b8);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5afeb8);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 13200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffc);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe00017);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x004cffb9);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff7500a8);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1feb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef90238);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111fc91);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604df);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0012f99b);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x012d07d2);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd07f714);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542097e);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff6a4);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9a086e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2dbf94b);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f380453);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6cfe82);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 13300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00080003);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffde0001);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0056ffe3);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff570064);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0113ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe8201d2);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x01cafcf0);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35049e);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155f9a6);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xffba080e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8cf689);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x03ce0a4e);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f5a8);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a50971);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf379f869);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eeb04ec);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef80fe4b);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 13400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000a);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe2ffec);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00540012);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e0015);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137ff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2e0145);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260fd86);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51041a);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0287f9fb);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4a0802);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x001df63f);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x02430aeb);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf4ce);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x08970a62);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf428f78f);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e950584);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xef97fe15);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 13500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000f);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffeaffda);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0046003d);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff5affc4);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04009d);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c8fe48);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99035a);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397fa96);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcec07ad);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x01adf637);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x00ac0b53);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef419);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x07730b3e);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e9f6bd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35061a);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb1fddf);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 13600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00000012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfff6ffcd);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x002f0061);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff7bff79);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x011e007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe08ffe8);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f9ff28);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17026a);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0479fb70);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbad0713);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x032ff672);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xff100b83);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff38b);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x063c0c04);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5baf5f5);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dcc06ae);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcdfda8);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 13700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0004ffc8);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00100078);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffacff3e);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e200f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe39ff35);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f10017);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd30156);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0521fc7f);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9c0638);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x0499f6ee);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7a0b7c);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f325);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f40cb3);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69af537);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5a073f);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xefecfd72);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 13800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0011ffcb);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0007f);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffe7ff19);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x008f014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94fe93);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b00105);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3002f);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x0585fdb7);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c10525);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x05def7a8);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf20b3c);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f2e9);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a00d48);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf787f484);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdf07cd);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00dfd3c);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 13900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80008);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001bffd7);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10076);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0026ff0e);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x002c0184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0ffe10);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x023b01e0);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff06);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a2ff09);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf92703e4);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f4f89b);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa820ac5);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f2d9);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x02430dc3);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf881f3dc);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5c0859);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf031fd06);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 14000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80001);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0021ffe8);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffba005d);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0060ff1f);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc40198);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0fdb5);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x019a029a);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fdea);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x05750067);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4027f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d4f9c0);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf9320a1a);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f2f3);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0x00df0e22);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xf986f341);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd108e2);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058fcd1);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 14100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0021fffd);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0038);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x008eff4a);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff630184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x003afd8b);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x00da0326);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fced);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x050101c0);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cb0103);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x0876fb10);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80a093e);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f338);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7a0e66);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa94f2b2);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3f0967);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf081fc9b);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 14200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff3);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001d0013);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa000b);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00aaff89);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x00cefd95);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x000a037b);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fc1d);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x044c0305);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90cff7e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5fc81);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7100834);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff3a7);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe160e8d);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaaf231);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa509e9);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0adfc65);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 14300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffef);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00140025);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffdd);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2ffd6);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedb00f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150fdd3);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xff380391);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb85);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x035e0426);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xf994fdfe);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08eefe0b);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6490702);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f43e);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb60e97);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc6f1be);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a040a67);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0dbfc30);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 14400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0002ffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00070033);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ffb4);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00a40027);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b4fe3f);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe760369);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb2e);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x02450518);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5ffc90);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1ffa1);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bc05ae);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902f4fc);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb600e85);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde7f15a);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x095d0ae2);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10cfbfb);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 14500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0005ffef);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfffa0038);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff95);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00820074);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f0fed0);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd20304);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb1d);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x010e05ce);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb64fb41);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x084e013b);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569043e);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00f5dd);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa150e55);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0bf104);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b00b59);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13ffbc6);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 14600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fff4);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffed0035);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff83);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x005000b4);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6ff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ffff7a);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd580269);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fb53);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xffca0640);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc99fa1e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x079a02cb);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55502ba);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5f6e0);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d90e0a);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0031f0bd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fd0bcb);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174fb91);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 14700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0009fffb);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4002a);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ff82);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x001400e0);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3cff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e10030);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1201a4);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fbcd);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88066a);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf1f92f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aa0449);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57e0128);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7ef801);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b00da2);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0156f086);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x07450c39);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1acfb5c);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 14800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00080002);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0019);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x003fff92);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffd600f1);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96feb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x019700e1);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0500c2);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fc84);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd590649);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5df87f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x058505aa);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4ff91);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9f93c);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69d0d20);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0279f05e);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x06880ca3);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e6fb28);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 14900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x00060009);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0004);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0051ffb0);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff9d00e8);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffcfe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x01280180);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32ffd2);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fd6e);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4d05df);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d1f812);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x043506e4);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf685fdfb);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fa8d);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a10c83);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0399f046);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c70d08);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222faf3);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 15000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffe5ffef);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x0057ffd9);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff7000c4);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0062fe68);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x009e01ff);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95fee6);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0435fe7d);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb710530);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x023cf7ee);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c307ef);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75efc70);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5cfbef);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c10bce);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b3f03f);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x05030d69);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf261fabf);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 15100000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xffefffdc);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00510006);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff540089);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00befe7c);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0x00060253);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe27fe0d);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413ffa2);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad10446);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0390f812);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0x013b08c3);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868faf6);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fd5f);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fd0b02);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c7f046);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x043b0dc4);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a1fa8b);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 15200000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0012);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0xfffbffce);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x003f0033);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e003f);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106feb6);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6e0276);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeddfd56);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000cc);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa740329);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bff87f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaa095d);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99ef995);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9fed8);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3590a1f);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d2f05e);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x03700e1b);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e4fa58);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 15300000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9000f);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0009ffc8);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00250059);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff5effee);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0132ff10);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee30265);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaafccf);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x031101eb);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6001e8);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bdf92f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1b09b6);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafaf852);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0055);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d50929);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d3f086);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a30e6c);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf329fa24);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 15400000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80009);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0015ffca);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0x00050074);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xff81ff9f);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x013dff82);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe710221);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x007cfc80);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x024102ed);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa940090);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0680fa1e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9b09cd);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc73f736);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad501d0);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2740820);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c9f0bd);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d40eb9);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371f9f1);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 15500000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80002);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001effd5);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5007f);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff5b);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2401b0);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0146fc70);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d03c6);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb10ff32);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0701fb41);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb3709a1);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f644);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000345);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2350708);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b2f104);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x01050eff);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3baf9be);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 15600000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0022ffe6);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9007a);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff29);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2007e);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01011b);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f6fc9e);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440467);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbccfdde);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738fc90);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f70934);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99f582);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x090204b0);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21a05e1);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8df15a);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0x00340f41);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf405f98b);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 15700000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcfff4);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x0020fffa);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40064);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x002fff11);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a400f0);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0d006e);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x0281fd09);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604c9);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbffca2);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0726fdfe);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e80888);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134f4f3);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1060c);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf22304af);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b59f1be);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xff640f7d);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf452f959);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 15800000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0000fff0);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0010);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa0041);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0067ff13);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043014a);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46ffb9);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02dbfda8);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3504e5);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddcfb8d);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9ff7e);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf81107a2);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9f49a);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0753);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2500373);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c14f231);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930fb3);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a1f927);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 15900000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0003ffee);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x000f0023);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0016);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x0093ff31);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdc0184);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6ff09);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fdfe70);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5104ba);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0xff15faac);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270103);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7780688);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x044df479);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430883);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a00231);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbef2b2);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc40fe3);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2f8f5);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+
+ case 16000000:
+ cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+ cx25840_write4(client, DIF_BPF_COEFF23, 0x0006ffef);
+ cx25840_write4(client, DIF_BPF_COEFF45, 0x00020031);
+ cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffe8);
+ cx25840_write4(client, DIF_BPF_COEFF89, 0x00adff66);
+ cx25840_write4(client, DIF_BPF_COEFF1011, 0xff790198);
+ cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe6e);
+ cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e5ff55);
+ cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99044a);
+ cx25840_write4(client, DIF_BPF_COEFF1819, 0x005bfa09);
+ cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545027f);
+ cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7230541);
+ cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b8f490);
+ cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20997);
+ cx25840_write4(client, DIF_BPF_COEFF2829, 0xf31300eb);
+ cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d55f341);
+ cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6100e);
+ cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544f8c3);
+ cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+ break;
+ }
+}
+
+static void cx23885_std_setup(struct i2c_client *client)
+{
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+ v4l2_std_id std = state->std;
+ u32 ifHz;
+
+ cx25840_write4(client, 0x478, 0x6628021F);
+ cx25840_write4(client, 0x400, 0x0);
+ cx25840_write4(client, 0x4b4, 0x20524030);
+ cx25840_write4(client, 0x47c, 0x010a8263);
+
+ if (std & V4L2_STD_NTSC) {
+ v4l_dbg(1, cx25840_debug, client, "%s() Selecting NTSC",
+ __func__);
+
+ /* Horiz / vert timing */
+ cx25840_write4(client, 0x428, 0x1e1e601a);
+ cx25840_write4(client, 0x424, 0x5b2d007a);
+
+ /* DIF NTSC */
+ cx25840_write4(client, 0x304, 0x6503bc0c);
+ cx25840_write4(client, 0x308, 0xbd038c85);
+ cx25840_write4(client, 0x30c, 0x1db4640a);
+ cx25840_write4(client, 0x310, 0x00008800);
+ cx25840_write4(client, 0x314, 0x44400400);
+ cx25840_write4(client, 0x32c, 0x0c800800);
+ cx25840_write4(client, 0x330, 0x27000100);
+ cx25840_write4(client, 0x334, 0x1f296e1f);
+ cx25840_write4(client, 0x338, 0x009f50c1);
+ cx25840_write4(client, 0x340, 0x1befbf06);
+ cx25840_write4(client, 0x344, 0x000035e8);
+
+ /* DIF I/F */
+ ifHz = 5400000;
+
+ } else {
+ v4l_dbg(1, cx25840_debug, client, "%s() Selecting PAL-BG",
+ __func__);
+
+ /* Horiz / vert timing */
+ cx25840_write4(client, 0x428, 0x28244024);
+ cx25840_write4(client, 0x424, 0x5d2d0084);
+
+ /* DIF */
+ cx25840_write4(client, 0x304, 0x6503bc0c);
+ cx25840_write4(client, 0x308, 0xbd038c85);
+ cx25840_write4(client, 0x30c, 0x1db4640a);
+ cx25840_write4(client, 0x310, 0x00008800);
+ cx25840_write4(client, 0x314, 0x44400600);
+ cx25840_write4(client, 0x32c, 0x0c800800);
+ cx25840_write4(client, 0x330, 0x27000100);
+ cx25840_write4(client, 0x334, 0x213530ec);
+ cx25840_write4(client, 0x338, 0x00a65ba8);
+ cx25840_write4(client, 0x340, 0x1befbf06);
+ cx25840_write4(client, 0x344, 0x000035e8);
+
+ /* DIF I/F */
+ ifHz = 6000000;
+ }
+
+ cx23885_dif_setup(client, ifHz);
+
+ /* Explicitly ensure the inputs are reconfigured after
+ * a standard change.
+ */
+ set_input(client, state->vid_input, state->aud_input);
+}
+
+/* ----------------------------------------------------------------------- */
+
static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {
.s_ctrl = cx25840_s_ctrl,
};
@@ -1801,6 +5024,7 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
.s_std = cx25840_s_std,
+ .g_std = cx25840_g_std,
.reset = cx25840_reset,
.load_fw = cx25840_load_fw,
.s_io_pin_config = common_s_io_pin_config,
@@ -1828,6 +5052,7 @@ static const struct v4l2_subdev_video_ops cx25840_video_ops = {
.s_routing = cx25840_s_video_routing,
.s_mbus_fmt = cx25840_s_mbus_fmt,
.s_stream = cx25840_s_stream,
+ .g_input_status = cx25840_g_input_status,
};
static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = {
@@ -2076,15 +5301,4 @@ static struct i2c_driver cx25840_driver = {
.id_table = cx25840_id,
};
-static __init int init_cx25840(void)
-{
- return i2c_add_driver(&cx25840_driver);
-}
-
-static __exit void exit_cx25840(void)
-{
- i2c_del_driver(&cx25840_driver);
-}
-
-module_init(init_cx25840);
-module_exit(exit_cx25840);
+module_i2c_driver(cx25840_driver);
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 5c42abdf422f..3598dc087b08 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -70,11 +70,6 @@ config VIDEO_CX88_DVB
To compile this driver as a module, choose M here: the
module will be called cx88-dvb.
-config VIDEO_CX88_MPEG
- tristate
- depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD
- default y
-
config VIDEO_CX88_VP3054
tristate "VP-3054 Secondary I2C Bus Support"
default m
@@ -84,3 +79,8 @@ config VIDEO_CX88_VP3054
Conexant 2388x chip and the MT352 demodulator,
which also require support for the VP-3054
Secondary I2C bus, such at DNTV Live! DVB-T Pro.
+
+config VIDEO_CX88_MPEG
+ tristate
+ depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD
+ default y
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 68d1240f493c..04bf6627d362 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -96,7 +96,7 @@ typedef struct cx88_audio_dev snd_cx88_card_t;
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 0d719faafd8a..cbd5d119a2c6 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1306,7 +1306,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_WINFAST_DTV2000H_J] = {
.name = "WinFast DTV2000 H rev. J",
- .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .tuner_type = TUNER_PHILIPS_FMD1216MEX_MK3,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1573,8 +1573,8 @@ static const struct cx88_board cx88_boards[] = {
.name = "Pinnacle Hybrid PCTV",
.tuner_type = TUNER_XC2028,
.tuner_addr = 0x61,
- .radio_type = TUNER_XC2028,
- .radio_addr = 0x61,
+ .radio_type = UNSET,
+ .radio_addr = ADDR_UNSET,
.input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -1611,8 +1611,8 @@ static const struct cx88_board cx88_boards[] = {
.name = "Leadtek TV2000 XP Global",
.tuner_type = TUNER_XC2028,
.tuner_addr = 0x61,
- .radio_type = TUNER_XC2028,
- .radio_addr = 0x61,
+ .radio_type = UNSET,
+ .radio_addr = ADDR_UNSET,
.input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -1643,6 +1643,78 @@ static const struct cx88_board cx88_boards[] = {
.gpio3 = 0x0000,
},
},
+ [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36] = {
+ .name = "Leadtek TV2000 XP Global (SC4100)",
+ .tuner_type = TUNER_XC4000,
+ .tuner_addr = 0x61,
+ .radio_type = UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = { {
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x0000,
+ .gpio2 = 0x0C04, /* pin 18 = 1, pin 19 = 0 */
+ .gpio3 = 0x0000,
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x0000,
+ .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */
+ .gpio3 = 0x0000,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x0000,
+ .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */
+ .gpio3 = 0x0000,
+ } },
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x0000,
+ .gpio2 = 0x0C00, /* pin 18 = 0, pin 19 = 0 */
+ .gpio3 = 0x0000,
+ },
+ },
+ [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43] = {
+ .name = "Leadtek TV2000 XP Global (XC4100)",
+ .tuner_type = TUNER_XC4000,
+ .tuner_addr = 0x61,
+ .radio_type = UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = { {
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x6040, /* pin 14 = 1, pin 13 = 0 */
+ .gpio2 = 0x0000,
+ .gpio3 = 0x0000,
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x6060, /* pin 14 = 1, pin 13 = 1 */
+ .gpio2 = 0x0000,
+ .gpio3 = 0x0000,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x6060, /* pin 14 = 1, pin 13 = 1 */
+ .gpio2 = 0x0000,
+ .gpio3 = 0x0000,
+ } },
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x6000, /* pin 14 = 1, pin 13 = 0 */
+ .gpio2 = 0x0000,
+ .gpio3 = 0x0000,
+ },
+ },
[CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
.name = "PowerColor RA330", /* Long names may confuse LIRC. */
.tuner_type = TUNER_XC2028,
@@ -2043,8 +2115,8 @@ static const struct cx88_board cx88_boards[] = {
.name = "Terratec Cinergy HT PCI MKII",
.tuner_type = TUNER_XC2028,
.tuner_addr = 0x61,
- .radio_type = TUNER_XC2028,
- .radio_addr = 0x61,
+ .radio_type = UNSET,
+ .radio_addr = ADDR_UNSET,
.input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -2082,9 +2154,9 @@ static const struct cx88_board cx88_boards[] = {
[CX88_BOARD_WINFAST_DTV1800H] = {
.name = "Leadtek WinFast DTV1800 Hybrid",
.tuner_type = TUNER_XC2028,
- .radio_type = TUNER_XC2028,
+ .radio_type = UNSET,
.tuner_addr = 0x61,
- .radio_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
/*
* GPIO setting
*
@@ -2123,9 +2195,9 @@ static const struct cx88_board cx88_boards[] = {
[CX88_BOARD_WINFAST_DTV1800H_XC4000] = {
.name = "Leadtek WinFast DTV1800 H (XC4000)",
.tuner_type = TUNER_XC4000,
- .radio_type = TUNER_XC4000,
+ .radio_type = UNSET,
.tuner_addr = 0x61,
- .radio_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
/*
* GPIO setting
*
@@ -2164,9 +2236,9 @@ static const struct cx88_board cx88_boards[] = {
[CX88_BOARD_WINFAST_DTV2000H_PLUS] = {
.name = "Leadtek WinFast DTV2000 H PLUS",
.tuner_type = TUNER_XC4000,
- .radio_type = TUNER_XC4000,
+ .radio_type = UNSET,
.tuner_addr = 0x61,
- .radio_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
/*
* GPIO
* 2: 1: mute audio
@@ -2719,6 +2791,21 @@ static const struct cx88_subid cx88_subids[] = {
.subdevice = 0x6618,
.card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
}, {
+ /* TV2000 XP Global [107d:6618] */
+ .subvendor = 0x107d,
+ .subdevice = 0x6619,
+ .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
+ }, {
+ /* WinFast TV2000 XP Global with XC4000 tuner */
+ .subvendor = 0x107d,
+ .subdevice = 0x6f36,
+ .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36,
+ }, {
+ /* WinFast TV2000 XP Global with XC4000 tuner and different GPIOs */
+ .subvendor = 0x107d,
+ .subdevice = 0x6f43,
+ .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43,
+ }, {
.subvendor = 0xb034,
.subdevice = 0x3034,
.card = CX88_BOARD_PROF_7301,
@@ -3075,6 +3162,8 @@ static int cx88_xc4000_tuner_callback(struct cx88_core *core,
switch (core->boardnr) {
case CX88_BOARD_WINFAST_DTV1800H_XC4000:
case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
return cx88_xc4000_winfast2000h_plus_callback(core,
command, arg);
}
@@ -3232,6 +3321,7 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
cx_set(MO_GP0_IO, 0x00001010);
break;
+ case CX88_BOARD_WINFAST_DTV2000H_J:
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR4000:
/* Init GPIO */
@@ -3250,6 +3340,8 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
case CX88_BOARD_WINFAST_DTV1800H_XC4000:
case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
cx88_xc4000_winfast2000h_plus_callback(core,
XC4000_TUNER_RESET, 0);
break;
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index cf3d33ab541b..003937cd72f5 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -815,9 +815,9 @@ static const u8 samsung_smt_7020_inittab[] = {
};
-static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx8802_dev *dev = fe->dvb->priv;
u8 buf[4];
u32 div;
@@ -827,14 +827,14 @@ static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe,
.buf = buf,
.len = sizeof(buf) };
- div = params->frequency / 125;
+ div = c->frequency / 125;
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
buf[2] = 0x84; /* 0xC4 */
buf[3] = 0x00;
- if (params->frequency < 1500000)
+ if (c->frequency < 1500000)
buf[3] |= 0x10;
if (fe->ops.i2c_gate_ctrl)
@@ -954,6 +954,7 @@ static int dvb_register(struct cx8802_dev *dev)
struct cx88_core *core = dev->core;
struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
int mfe_shared = 0; /* bus not shared by default */
+ int res = -EINVAL;
if (0 != core->i2c_rc) {
printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name);
@@ -999,7 +1000,6 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
case CX88_BOARD_WINFAST_DTV2000H:
- case CX88_BOARD_WINFAST_DTV2000H_J:
case CX88_BOARD_HAUPPAUGE_HVR1100:
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
case CX88_BOARD_HAUPPAUGE_HVR1300:
@@ -1013,6 +1013,17 @@ static int dvb_register(struct cx8802_dev *dev)
goto frontend_detach;
}
break;
+ case CX88_BOARD_WINFAST_DTV2000H_J:
+ fe0->dvb.frontend = dvb_attach(cx22702_attach,
+ &hauppauge_hvr_config,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216MEX_MK3))
+ goto frontend_detach;
+ }
+ break;
case CX88_BOARD_HAUPPAUGE_HVR3000:
/* MFE frontend 1 */
mfe_shared = 1;
@@ -1566,13 +1577,16 @@ static int dvb_register(struct cx8802_dev *dev)
call_all(core, core, s_power, 0);
/* register everything */
- return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
- &dev->pci->dev, adapter_nr, mfe_shared, NULL);
+ res = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+ &dev->pci->dev, adapter_nr, mfe_shared, NULL);
+ if (res)
+ goto frontend_detach;
+ return res;
frontend_detach:
core->gate_ctrl = NULL;
videobuf_dvb_dealloc_frontends(&dev->frontends);
- return -EINVAL;
+ return res;
}
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index a1fe0abb6e43..de0f1af74e41 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -132,7 +132,7 @@ static void do_i2c_scan(const char *name, struct i2c_client *c)
}
}
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
{
/* Prevents usage of invalid delay values */
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index e614201b5ed3..ebf448c48ca3 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -103,6 +103,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
case CX88_BOARD_WINFAST_DTV1800H_XC4000:
case CX88_BOARD_WINFAST_DTV2000H_PLUS:
case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
auxgpio = gpio;
break;
@@ -302,6 +304,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_WINFAST2000XP_EXPERT:
case CX88_BOARD_WINFAST_DTV1000:
case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
ir_codes = RC_MAP_WINFAST;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index fa8d307e1a3d..c9659def2a78 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -244,6 +244,8 @@ extern const struct sram_channel const cx88_sram_channels[];
#define CX88_BOARD_TEVII_S464 86
#define CX88_BOARD_WINFAST_DTV2000H_PLUS 87
#define CX88_BOARD_WINFAST_DTV1800H_XC4000 88
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c
index bd443ee76fff..5b68847d4017 100644
--- a/drivers/media/video/davinci/dm355_ccdc.c
+++ b/drivers/media/video/davinci/dm355_ccdc.c
@@ -292,7 +292,7 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
if ((ccdcparam->med_filt_thres < 0) ||
(ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
dev_dbg(ccdc_cfg.dev,
- "Invalid value of median filter thresold\n");
+ "Invalid value of median filter threshold\n");
return -EINVAL;
}
@@ -1069,15 +1069,4 @@ static struct platform_driver dm355_ccdc_driver = {
.probe = dm355_ccdc_probe,
};
-static int __init dm355_ccdc_init(void)
-{
- return platform_driver_register(&dm355_ccdc_driver);
-}
-
-static void __exit dm355_ccdc_exit(void)
-{
- platform_driver_unregister(&dm355_ccdc_driver);
-}
-
-module_init(dm355_ccdc_init);
-module_exit(dm355_ccdc_exit);
+module_platform_driver(dm355_ccdc_driver);
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c
index 8051c2956478..9303fe553b07 100644
--- a/drivers/media/video/davinci/dm644x_ccdc.c
+++ b/drivers/media/video/davinci/dm644x_ccdc.c
@@ -1078,15 +1078,4 @@ static struct platform_driver dm644x_ccdc_driver = {
.probe = dm644x_ccdc_probe,
};
-static int __init dm644x_ccdc_init(void)
-{
- return platform_driver_register(&dm644x_ccdc_driver);
-}
-
-static void __exit dm644x_ccdc_exit(void)
-{
- platform_driver_unregister(&dm644x_ccdc_driver);
-}
-
-module_init(dm644x_ccdc_init);
-module_exit(dm644x_ccdc_exit);
+module_platform_driver(dm644x_ccdc_driver);
diff --git a/drivers/media/video/davinci/isif.c b/drivers/media/video/davinci/isif.c
index 29c29c668596..5278fe7d6d0c 100644
--- a/drivers/media/video/davinci/isif.c
+++ b/drivers/media/video/davinci/isif.c
@@ -34,6 +34,7 @@
#include <linux/videodev2.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/module.h>
#include <mach/mux.h>
@@ -1156,17 +1157,6 @@ static struct platform_driver isif_driver = {
.probe = isif_probe,
};
-static int __init isif_init(void)
-{
- return platform_driver_register(&isif_driver);
-}
-
-static void isif_exit(void)
-{
- platform_driver_unregister(&isif_driver);
-}
-
-module_init(isif_init);
-module_exit(isif_exit);
+module_platform_driver(isif_driver);
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c
index d773d30de221..c4a82a1a8a97 100644
--- a/drivers/media/video/davinci/vpbe.c
+++ b/drivers/media/video/davinci/vpbe.c
@@ -141,11 +141,12 @@ static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev,
return 0;
}
-static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode)
+static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode,
+ int output_index)
{
struct vpbe_config *cfg = vpbe_dev->cfg;
struct vpbe_enc_mode_info var;
- int curr_output = vpbe_dev->current_out_index;
+ int curr_output = output_index;
int i;
if (NULL == mode)
@@ -245,6 +246,8 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
struct encoder_config_info *curr_enc_info =
vpbe_current_encoder_info(vpbe_dev);
struct vpbe_config *cfg = vpbe_dev->cfg;
+ struct venc_platform_data *venc_device = vpbe_dev->venc_device;
+ enum v4l2_mbus_pixelcode if_params;
int enc_out_index;
int sd_index;
int ret = 0;
@@ -274,6 +277,8 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
goto out;
}
+ if_params = cfg->outputs[index].if_params;
+ venc_device->setup_if_config(if_params);
if (ret)
goto out;
}
@@ -293,7 +298,7 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
* encoder.
*/
ret = vpbe_get_mode_info(vpbe_dev,
- cfg->outputs[index].default_mode);
+ cfg->outputs[index].default_mode, index);
if (!ret) {
struct osd_state *osd_device = vpbe_dev->osd_device;
@@ -367,6 +372,11 @@ static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev,
ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
s_dv_preset, dv_preset);
+ if (!ret && (vpbe_dev->amp != NULL)) {
+ /* Call amplifier subdevice */
+ ret = v4l2_subdev_call(vpbe_dev->amp, video,
+ s_dv_preset, dv_preset);
+ }
/* set the lcd controller output for the given mode */
if (!ret) {
struct osd_state *osd_device = vpbe_dev->osd_device;
@@ -566,6 +576,8 @@ static int platform_device_get(struct device *dev, void *data)
if (strcmp("vpbe-osd", pdev->name) == 0)
vpbe_dev->osd_device = platform_get_drvdata(pdev);
+ if (strcmp("vpbe-venc", pdev->name) == 0)
+ vpbe_dev->venc_device = dev_get_platdata(&pdev->dev);
return 0;
}
@@ -584,6 +596,7 @@ static int platform_device_get(struct device *dev, void *data)
static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
{
struct encoder_config_info *enc_info;
+ struct amp_config_info *amp_info;
struct v4l2_subdev **enc_subdev;
struct osd_state *osd_device;
struct i2c_adapter *i2c_adap;
@@ -704,6 +717,32 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders"
" currently not supported");
}
+ /* Add amplifier subdevice for dm365 */
+ if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) &&
+ vpbe_dev->cfg->amp != NULL) {
+ amp_info = vpbe_dev->cfg->amp;
+ if (amp_info->is_i2c) {
+ vpbe_dev->amp = v4l2_i2c_new_subdev_board(
+ &vpbe_dev->v4l2_dev, i2c_adap,
+ &amp_info->board_info, NULL);
+ if (!vpbe_dev->amp) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "amplifier %s failed to register",
+ amp_info->module_name);
+ ret = -ENODEV;
+ goto vpbe_fail_amp_register;
+ }
+ v4l2_info(&vpbe_dev->v4l2_dev,
+ "v4l2 sub device %s registered\n",
+ amp_info->module_name);
+ } else {
+ vpbe_dev->amp = NULL;
+ v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers"
+ " currently not supported");
+ }
+ } else {
+ vpbe_dev->amp = NULL;
+ }
/* set the current encoder and output to that of venc by default */
vpbe_dev->current_sd_index = 0;
@@ -731,6 +770,8 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
/* TBD handling of bootargs for default output and mode */
return 0;
+vpbe_fail_amp_register:
+ kfree(vpbe_dev->amp);
vpbe_fail_sd_register:
kfree(vpbe_dev->encoders);
vpbe_fail_v4l2_device:
@@ -757,6 +798,7 @@ static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev)
if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0)
clk_put(vpbe_dev->dac_clk);
+ kfree(vpbe_dev->amp);
kfree(vpbe_dev->encoders);
vpbe_dev->initialized = 0;
/* disable vpss clocks */
@@ -811,8 +853,10 @@ static __devinit int vpbe_probe(struct platform_device *pdev)
if (cfg->outputs->num_modes > 0)
vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0];
- else
+ else {
+ kfree(vpbe_dev);
return -ENODEV;
+ }
/* set the driver data in platform device */
platform_set_drvdata(pdev, vpbe_dev);
@@ -839,26 +883,4 @@ static struct platform_driver vpbe_driver = {
.remove = vpbe_remove,
};
-/**
- * vpbe_init: initialize the vpbe driver
- *
- * This function registers device and driver to the kernel
- */
-static __init int vpbe_init(void)
-{
- return platform_driver_register(&vpbe_driver);
-}
-
-/**
- * vpbe_cleanup : cleanup function for vpbe driver
- *
- * This will un-registers the device and driver to the kernel
- */
-static void vpbe_cleanup(void)
-{
- platform_driver_unregister(&vpbe_driver);
-}
-
-/* Function for module initialization and cleanup */
-module_init(vpbe_init);
-module_exit(vpbe_cleanup);
+module_platform_driver(vpbe_driver);
diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c
index 8588a86d9b45..1f3b1c729252 100644
--- a/drivers/media/video/davinci/vpbe_display.c
+++ b/drivers/media/video/davinci/vpbe_display.c
@@ -1746,15 +1746,16 @@ static __devinit int vpbe_display_probe(struct platform_device *pdev)
for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
if (register_device(disp_dev->dev[i], disp_dev, pdev)) {
err = -ENODEV;
- goto probe_out;
+ goto probe_out_irq;
}
}
printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n");
return 0;
-probe_out:
+probe_out_irq:
free_irq(res->start, disp_dev);
+probe_out:
for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) {
/* Get the pointer to the layer object */
vpbe_display_layer = disp_dev->dev[k];
@@ -1816,43 +1817,7 @@ static struct platform_driver vpbe_display_driver = {
.remove = __devexit_p(vpbe_display_remove),
};
-/*
- * vpbe_display_init()
- * This function registers device and driver to the kernel, requests irq
- * handler and allocates memory for layer objects
- */
-static __devinit int vpbe_display_init(void)
-{
- int err;
-
- printk(KERN_DEBUG "vpbe_display_init\n");
-
- /* Register driver to the kernel */
- err = platform_driver_register(&vpbe_display_driver);
- if (0 != err)
- return err;
-
- printk(KERN_DEBUG "vpbe_display_init:"
- "VPBE V4L2 Display Driver V1.0 loaded\n");
- return 0;
-}
-
-/*
- * vpbe_display_cleanup()
- * This function un-registers device and driver to the kernel, frees requested
- * irq handler and de-allocates memory allocated for layer objects.
- */
-static void vpbe_display_cleanup(void)
-{
- printk(KERN_DEBUG "vpbe_display_cleanup\n");
-
- /* platform driver unregister */
- platform_driver_unregister(&vpbe_display_driver);
-}
-
-/* Function for module initialization and cleanup */
-module_init(vpbe_display_init);
-module_exit(vpbe_display_cleanup);
+module_platform_driver(vpbe_display_driver);
MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c
index ceccf4302518..bba299dbf396 100644
--- a/drivers/media/video/davinci/vpbe_osd.c
+++ b/drivers/media/video/davinci/vpbe_osd.c
@@ -28,7 +28,6 @@
#include <linux/clk.h>
#include <linux/slab.h>
-#include <mach/io.h>
#include <mach/cputype.h>
#include <mach/hardware.h>
@@ -248,11 +247,29 @@ static void _osd_set_rec601_attenuation(struct osd_state *sd,
osd_modify(sd, OSD_OSDWIN0MD_ATN0E,
enable ? OSD_OSDWIN0MD_ATN0E : 0,
OSD_OSDWIN0MD);
+ if (sd->vpbe_type == VPBE_VERSION_1)
+ osd_modify(sd, OSD_OSDWIN0MD_ATN0E,
+ enable ? OSD_OSDWIN0MD_ATN0E : 0,
+ OSD_OSDWIN0MD);
+ else if ((sd->vpbe_type == VPBE_VERSION_3) ||
+ (sd->vpbe_type == VPBE_VERSION_2))
+ osd_modify(sd, OSD_EXTMODE_ATNOSD0EN,
+ enable ? OSD_EXTMODE_ATNOSD0EN : 0,
+ OSD_EXTMODE);
break;
case OSDWIN_OSD1:
osd_modify(sd, OSD_OSDWIN1MD_ATN1E,
enable ? OSD_OSDWIN1MD_ATN1E : 0,
OSD_OSDWIN1MD);
+ if (sd->vpbe_type == VPBE_VERSION_1)
+ osd_modify(sd, OSD_OSDWIN1MD_ATN1E,
+ enable ? OSD_OSDWIN1MD_ATN1E : 0,
+ OSD_OSDWIN1MD);
+ else if ((sd->vpbe_type == VPBE_VERSION_3) ||
+ (sd->vpbe_type == VPBE_VERSION_2))
+ osd_modify(sd, OSD_EXTMODE_ATNOSD1EN,
+ enable ? OSD_EXTMODE_ATNOSD1EN : 0,
+ OSD_EXTMODE);
break;
}
}
@@ -273,15 +290,71 @@ static void _osd_set_blending_factor(struct osd_state *sd,
}
}
+static void _osd_enable_rgb888_pixblend(struct osd_state *sd,
+ enum osd_win_layer osdwin)
+{
+
+ osd_modify(sd, OSD_MISCCTL_BLDSEL, 0, OSD_MISCCTL);
+ switch (osdwin) {
+ case OSDWIN_OSD0:
+ osd_modify(sd, OSD_EXTMODE_OSD0BLDCHR,
+ OSD_EXTMODE_OSD0BLDCHR, OSD_EXTMODE);
+ break;
+ case OSDWIN_OSD1:
+ osd_modify(sd, OSD_EXTMODE_OSD1BLDCHR,
+ OSD_EXTMODE_OSD1BLDCHR, OSD_EXTMODE);
+ break;
+ }
+}
+
static void _osd_enable_color_key(struct osd_state *sd,
enum osd_win_layer osdwin,
unsigned colorkey,
enum osd_pix_format pixfmt)
{
switch (pixfmt) {
+ case PIXFMT_1BPP:
+ case PIXFMT_2BPP:
+ case PIXFMT_4BPP:
+ case PIXFMT_8BPP:
+ if (sd->vpbe_type == VPBE_VERSION_3) {
+ switch (osdwin) {
+ case OSDWIN_OSD0:
+ osd_modify(sd, OSD_TRANSPBMPIDX_BMP0,
+ colorkey <<
+ OSD_TRANSPBMPIDX_BMP0_SHIFT,
+ OSD_TRANSPBMPIDX);
+ break;
+ case OSDWIN_OSD1:
+ osd_modify(sd, OSD_TRANSPBMPIDX_BMP1,
+ colorkey <<
+ OSD_TRANSPBMPIDX_BMP1_SHIFT,
+ OSD_TRANSPBMPIDX);
+ break;
+ }
+ }
+ break;
case PIXFMT_RGB565:
- osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS,
- OSD_TRANSPVAL);
+ if (sd->vpbe_type == VPBE_VERSION_1)
+ osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS,
+ OSD_TRANSPVAL);
+ else if (sd->vpbe_type == VPBE_VERSION_3)
+ osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL,
+ OSD_TRANSPVALL);
+ break;
+ case PIXFMT_YCbCrI:
+ case PIXFMT_YCrCbI:
+ if (sd->vpbe_type == VPBE_VERSION_3)
+ osd_modify(sd, OSD_TRANSPVALU_Y, colorkey,
+ OSD_TRANSPVALU);
+ break;
+ case PIXFMT_RGB888:
+ if (sd->vpbe_type == VPBE_VERSION_3) {
+ osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL,
+ OSD_TRANSPVALL);
+ osd_modify(sd, OSD_TRANSPVALU_RGBU, colorkey >> 16,
+ OSD_TRANSPVALU);
+ }
break;
default:
break;
@@ -470,23 +543,188 @@ static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer,
return 0;
}
+#define OSD_SRC_ADDR_HIGH4 0x7800000
+#define OSD_SRC_ADDR_HIGH7 0x7F0000
+#define OSD_SRCADD_OFSET_SFT 23
+#define OSD_SRCADD_ADD_SFT 16
+#define OSD_WINADL_MASK 0xFFFF
+#define OSD_WINOFST_MASK 0x1000
+#define VPBE_REG_BASE 0x80000000
+
static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer,
unsigned long fb_base_phys,
unsigned long cbcr_ofst)
{
- switch (layer) {
- case WIN_OSD0:
- osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR);
- break;
- case WIN_VID0:
- osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
- break;
- case WIN_OSD1:
- osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR);
- break;
- case WIN_VID1:
- osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR);
- break;
+
+ if (sd->vpbe_type == VPBE_VERSION_1) {
+ switch (layer) {
+ case WIN_OSD0:
+ osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR);
+ break;
+ case WIN_VID0:
+ osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
+ break;
+ case WIN_OSD1:
+ osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR);
+ break;
+ case WIN_VID1:
+ osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR);
+ break;
+ }
+ } else if (sd->vpbe_type == VPBE_VERSION_3) {
+ unsigned long fb_offset_32 =
+ (fb_base_phys - VPBE_REG_BASE) >> 5;
+
+ switch (layer) {
+ case WIN_OSD0:
+ osd_modify(sd, OSD_OSDWINADH_O0AH,
+ fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+ OSD_OSDWINADH_O0AH_SHIFT),
+ OSD_OSDWINADH);
+ osd_write(sd, fb_offset_32 & OSD_OSDWIN0ADL_O0AL,
+ OSD_OSDWIN0ADL);
+ break;
+ case WIN_VID0:
+ osd_modify(sd, OSD_VIDWINADH_V0AH,
+ fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+ OSD_VIDWINADH_V0AH_SHIFT),
+ OSD_VIDWINADH);
+ osd_write(sd, fb_offset_32 & OSD_VIDWIN0ADL_V0AL,
+ OSD_VIDWIN0ADL);
+ break;
+ case WIN_OSD1:
+ osd_modify(sd, OSD_OSDWINADH_O1AH,
+ fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+ OSD_OSDWINADH_O1AH_SHIFT),
+ OSD_OSDWINADH);
+ osd_write(sd, fb_offset_32 & OSD_OSDWIN1ADL_O1AL,
+ OSD_OSDWIN1ADL);
+ break;
+ case WIN_VID1:
+ osd_modify(sd, OSD_VIDWINADH_V1AH,
+ fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+ OSD_VIDWINADH_V1AH_SHIFT),
+ OSD_VIDWINADH);
+ osd_write(sd, fb_offset_32 & OSD_VIDWIN1ADL_V1AL,
+ OSD_VIDWIN1ADL);
+ break;
+ }
+ } else if (sd->vpbe_type == VPBE_VERSION_2) {
+ struct osd_window_state *win = &sd->win[layer];
+ unsigned long fb_offset_32, cbcr_offset_32;
+
+ fb_offset_32 = fb_base_phys - VPBE_REG_BASE;
+ if (cbcr_ofst)
+ cbcr_offset_32 = cbcr_ofst;
+ else
+ cbcr_offset_32 = win->lconfig.line_length *
+ win->lconfig.ysize;
+ cbcr_offset_32 += fb_offset_32;
+ fb_offset_32 = fb_offset_32 >> 5;
+ cbcr_offset_32 = cbcr_offset_32 >> 5;
+ /*
+ * DM365: start address is 27-bit long address b26 - b23 are
+ * in offset register b12 - b9, and * bit 26 has to be '1'
+ */
+ if (win->lconfig.pixfmt == PIXFMT_NV12) {
+ switch (layer) {
+ case WIN_VID0:
+ case WIN_VID1:
+ /* Y is in VID0 */
+ osd_modify(sd, OSD_VIDWIN0OFST_V0AH,
+ ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+ (OSD_SRCADD_OFSET_SFT -
+ OSD_WINOFST_AH_SHIFT)) |
+ OSD_WINOFST_MASK, OSD_VIDWIN0OFST);
+ osd_modify(sd, OSD_VIDWINADH_V0AH,
+ (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+ (OSD_SRCADD_ADD_SFT -
+ OSD_VIDWINADH_V0AH_SHIFT),
+ OSD_VIDWINADH);
+ osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+ OSD_VIDWIN0ADL);
+ /* CbCr is in VID1 */
+ osd_modify(sd, OSD_VIDWIN1OFST_V1AH,
+ ((cbcr_offset_32 &
+ OSD_SRC_ADDR_HIGH4) >>
+ (OSD_SRCADD_OFSET_SFT -
+ OSD_WINOFST_AH_SHIFT)) |
+ OSD_WINOFST_MASK, OSD_VIDWIN1OFST);
+ osd_modify(sd, OSD_VIDWINADH_V1AH,
+ (cbcr_offset_32 &
+ OSD_SRC_ADDR_HIGH7) >>
+ (OSD_SRCADD_ADD_SFT -
+ OSD_VIDWINADH_V1AH_SHIFT),
+ OSD_VIDWINADH);
+ osd_write(sd, cbcr_offset_32 & OSD_WINADL_MASK,
+ OSD_VIDWIN1ADL);
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch (layer) {
+ case WIN_OSD0:
+ osd_modify(sd, OSD_OSDWIN0OFST_O0AH,
+ ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+ (OSD_SRCADD_OFSET_SFT -
+ OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK,
+ OSD_OSDWIN0OFST);
+ osd_modify(sd, OSD_OSDWINADH_O0AH,
+ (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+ (OSD_SRCADD_ADD_SFT -
+ OSD_OSDWINADH_O0AH_SHIFT), OSD_OSDWINADH);
+ osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+ OSD_OSDWIN0ADL);
+ break;
+ case WIN_VID0:
+ if (win->lconfig.pixfmt != PIXFMT_NV12) {
+ osd_modify(sd, OSD_VIDWIN0OFST_V0AH,
+ ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+ (OSD_SRCADD_OFSET_SFT -
+ OSD_WINOFST_AH_SHIFT)) |
+ OSD_WINOFST_MASK, OSD_VIDWIN0OFST);
+ osd_modify(sd, OSD_VIDWINADH_V0AH,
+ (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+ (OSD_SRCADD_ADD_SFT -
+ OSD_VIDWINADH_V0AH_SHIFT),
+ OSD_VIDWINADH);
+ osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+ OSD_VIDWIN0ADL);
+ }
+ break;
+ case WIN_OSD1:
+ osd_modify(sd, OSD_OSDWIN1OFST_O1AH,
+ ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+ (OSD_SRCADD_OFSET_SFT -
+ OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK,
+ OSD_OSDWIN1OFST);
+ osd_modify(sd, OSD_OSDWINADH_O1AH,
+ (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+ (OSD_SRCADD_ADD_SFT -
+ OSD_OSDWINADH_O1AH_SHIFT),
+ OSD_OSDWINADH);
+ osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+ OSD_OSDWIN1ADL);
+ break;
+ case WIN_VID1:
+ if (win->lconfig.pixfmt != PIXFMT_NV12) {
+ osd_modify(sd, OSD_VIDWIN1OFST_V1AH,
+ ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+ (OSD_SRCADD_OFSET_SFT -
+ OSD_WINOFST_AH_SHIFT)) |
+ OSD_WINOFST_MASK, OSD_VIDWIN1OFST);
+ osd_modify(sd, OSD_VIDWINADH_V1AH,
+ (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+ (OSD_SRCADD_ADD_SFT -
+ OSD_VIDWINADH_V1AH_SHIFT),
+ OSD_VIDWINADH);
+ osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+ OSD_VIDWIN1ADL);
+ }
+ break;
+ }
}
}
@@ -545,7 +783,7 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
{
struct osd_state *osd = sd;
struct osd_window_state *win = &osd->win[layer];
- int bad_config;
+ int bad_config = 0;
/* verify that the pixel format is compatible with the layer */
switch (lconfig->pixfmt) {
@@ -554,17 +792,25 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
case PIXFMT_4BPP:
case PIXFMT_8BPP:
case PIXFMT_RGB565:
- bad_config = !is_osd_win(layer);
+ if (osd->vpbe_type == VPBE_VERSION_1)
+ bad_config = !is_vid_win(layer);
break;
case PIXFMT_YCbCrI:
case PIXFMT_YCrCbI:
bad_config = !is_vid_win(layer);
break;
case PIXFMT_RGB888:
- bad_config = !is_vid_win(layer);
+ if (osd->vpbe_type == VPBE_VERSION_1)
+ bad_config = !is_vid_win(layer);
+ else if ((osd->vpbe_type == VPBE_VERSION_3) ||
+ (osd->vpbe_type == VPBE_VERSION_2))
+ bad_config = !is_osd_win(layer);
break;
case PIXFMT_NV12:
- bad_config = 1;
+ if (osd->vpbe_type != VPBE_VERSION_2)
+ bad_config = 1;
+ else
+ bad_config = is_osd_win(layer);
break;
case PIXFMT_OSD_ATTR:
bad_config = (layer != WIN_OSD1);
@@ -584,7 +830,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
/* DM6446: */
/* only one OSD window at a time can use RGB pixel formats */
- if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) {
+ if ((osd->vpbe_type == VPBE_VERSION_1) &&
+ is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) {
enum osd_pix_format pixfmt;
if (layer == WIN_OSD0)
pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt;
@@ -602,7 +849,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
}
/* DM6446: only one video window at a time can use RGB888 */
- if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) {
+ if ((osd->vpbe_type == VPBE_VERSION_1) && is_vid_win(layer) &&
+ lconfig->pixfmt == PIXFMT_RGB888) {
enum osd_pix_format pixfmt;
if (layer == WIN_VID0)
@@ -652,7 +900,8 @@ static void _osd_disable_vid_rgb888(struct osd_state *sd)
* The caller must ensure that neither video window is currently
* configured for RGB888 pixel format.
*/
- osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL);
+ if (sd->vpbe_type == VPBE_VERSION_1)
+ osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL);
}
static void _osd_enable_vid_rgb888(struct osd_state *sd,
@@ -665,13 +914,14 @@ static void _osd_enable_vid_rgb888(struct osd_state *sd,
* currently configured for RGB888 pixel format, as this routine will
* disable RGB888 pixel format for the other window.
*/
- if (layer == WIN_VID0) {
- osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
- OSD_MISCCTL_RGBEN, OSD_MISCCTL);
- } else if (layer == WIN_VID1) {
- osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
- OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
- OSD_MISCCTL);
+ if (sd->vpbe_type == VPBE_VERSION_1) {
+ if (layer == WIN_VID0)
+ osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+ OSD_MISCCTL_RGBEN, OSD_MISCCTL);
+ else if (layer == WIN_VID1)
+ osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+ OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+ OSD_MISCCTL);
}
}
@@ -697,9 +947,30 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
switch (layer) {
case WIN_OSD0:
- winmd_mask |= OSD_OSDWIN0MD_RGB0E;
- if (lconfig->pixfmt == PIXFMT_RGB565)
- winmd |= OSD_OSDWIN0MD_RGB0E;
+ if (sd->vpbe_type == VPBE_VERSION_1) {
+ winmd_mask |= OSD_OSDWIN0MD_RGB0E;
+ if (lconfig->pixfmt == PIXFMT_RGB565)
+ winmd |= OSD_OSDWIN0MD_RGB0E;
+ } else if ((sd->vpbe_type == VPBE_VERSION_3) ||
+ (sd->vpbe_type == VPBE_VERSION_2)) {
+ winmd_mask |= OSD_OSDWIN0MD_BMP0MD;
+ switch (lconfig->pixfmt) {
+ case PIXFMT_RGB565:
+ winmd |= (1 <<
+ OSD_OSDWIN0MD_BMP0MD_SHIFT);
+ break;
+ case PIXFMT_RGB888:
+ winmd |= (2 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
+ _osd_enable_rgb888_pixblend(sd, OSDWIN_OSD0);
+ break;
+ case PIXFMT_YCbCrI:
+ case PIXFMT_YCrCbI:
+ winmd |= (3 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
+ break;
+ default:
+ break;
+ }
+ }
winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0;
@@ -749,12 +1020,59 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
* For YUV420P format the register contents are
* duplicated in both VID registers
*/
+ if ((sd->vpbe_type == VPBE_VERSION_2) &&
+ (lconfig->pixfmt == PIXFMT_NV12)) {
+ /* other window also */
+ if (lconfig->interlaced) {
+ winmd_mask |= OSD_VIDWINMD_VFF1;
+ winmd |= OSD_VIDWINMD_VFF1;
+ osd_modify(sd, winmd_mask, winmd,
+ OSD_VIDWINMD);
+ }
+
+ osd_modify(sd, OSD_MISCCTL_S420D,
+ OSD_MISCCTL_S420D, OSD_MISCCTL);
+ osd_write(sd, lconfig->line_length >> 5,
+ OSD_VIDWIN1OFST);
+ osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP);
+ osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL);
+ /*
+ * if NV21 pixfmt and line length not 32B
+ * aligned (e.g. NTSC), Need to set window
+ * X pixel size to be 32B aligned as well
+ */
+ if (lconfig->xsize % 32) {
+ osd_write(sd,
+ ((lconfig->xsize + 31) & ~31),
+ OSD_VIDWIN1XL);
+ osd_write(sd,
+ ((lconfig->xsize + 31) & ~31),
+ OSD_VIDWIN0XL);
+ }
+ } else if ((sd->vpbe_type == VPBE_VERSION_2) &&
+ (lconfig->pixfmt != PIXFMT_NV12)) {
+ osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D,
+ OSD_MISCCTL);
+ }
+
if (lconfig->interlaced) {
osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP);
osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL);
+ if ((sd->vpbe_type == VPBE_VERSION_2) &&
+ lconfig->pixfmt == PIXFMT_NV12) {
+ osd_write(sd, lconfig->ypos >> 1,
+ OSD_VIDWIN1YP);
+ osd_write(sd, lconfig->ysize >> 1,
+ OSD_VIDWIN1YL);
+ }
} else {
osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP);
osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL);
+ if ((sd->vpbe_type == VPBE_VERSION_2) &&
+ lconfig->pixfmt == PIXFMT_NV12) {
+ osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP);
+ osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL);
+ }
}
break;
case WIN_OSD1:
@@ -764,14 +1082,43 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
* attribute mode to a normal mode.
*/
if (lconfig->pixfmt == PIXFMT_OSD_ATTR) {
- winmd_mask |=
- OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E |
- OSD_OSDWIN1MD_CLUTS1 |
- OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1;
+ if (sd->vpbe_type == VPBE_VERSION_1) {
+ winmd_mask |= OSD_OSDWIN1MD_ATN1E |
+ OSD_OSDWIN1MD_RGB1E | OSD_OSDWIN1MD_CLUTS1 |
+ OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1;
+ } else {
+ winmd_mask |= OSD_OSDWIN1MD_BMP1MD |
+ OSD_OSDWIN1MD_CLUTS1 | OSD_OSDWIN1MD_BLND1 |
+ OSD_OSDWIN1MD_TE1;
+ }
} else {
- winmd_mask |= OSD_OSDWIN1MD_RGB1E;
- if (lconfig->pixfmt == PIXFMT_RGB565)
- winmd |= OSD_OSDWIN1MD_RGB1E;
+ if (sd->vpbe_type == VPBE_VERSION_1) {
+ winmd_mask |= OSD_OSDWIN1MD_RGB1E;
+ if (lconfig->pixfmt == PIXFMT_RGB565)
+ winmd |= OSD_OSDWIN1MD_RGB1E;
+ } else if ((sd->vpbe_type == VPBE_VERSION_3)
+ || (sd->vpbe_type == VPBE_VERSION_2)) {
+ winmd_mask |= OSD_OSDWIN1MD_BMP1MD;
+ switch (lconfig->pixfmt) {
+ case PIXFMT_RGB565:
+ winmd |=
+ (1 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
+ break;
+ case PIXFMT_RGB888:
+ winmd |=
+ (2 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
+ _osd_enable_rgb888_pixblend(sd,
+ OSDWIN_OSD1);
+ break;
+ case PIXFMT_YCbCrI:
+ case PIXFMT_YCrCbI:
+ winmd |=
+ (3 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
+ break;
+ default:
+ break;
+ }
+ }
winmd_mask |= OSD_OSDWIN1MD_BMW1;
switch (lconfig->pixfmt) {
@@ -822,15 +1169,45 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
* For YUV420P format the register contents are
* duplicated in both VID registers
*/
- osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D,
- OSD_MISCCTL);
+ if (sd->vpbe_type == VPBE_VERSION_2) {
+ if (lconfig->pixfmt == PIXFMT_NV12) {
+ /* other window also */
+ if (lconfig->interlaced) {
+ winmd_mask |= OSD_VIDWINMD_VFF0;
+ winmd |= OSD_VIDWINMD_VFF0;
+ osd_modify(sd, winmd_mask, winmd,
+ OSD_VIDWINMD);
+ }
+ osd_modify(sd, OSD_MISCCTL_S420D,
+ OSD_MISCCTL_S420D, OSD_MISCCTL);
+ osd_write(sd, lconfig->line_length >> 5,
+ OSD_VIDWIN0OFST);
+ osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP);
+ osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL);
+ } else {
+ osd_modify(sd, OSD_MISCCTL_S420D,
+ ~OSD_MISCCTL_S420D, OSD_MISCCTL);
+ }
+ }
if (lconfig->interlaced) {
osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP);
osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL);
+ if ((sd->vpbe_type == VPBE_VERSION_2) &&
+ lconfig->pixfmt == PIXFMT_NV12) {
+ osd_write(sd, lconfig->ypos >> 1,
+ OSD_VIDWIN0YP);
+ osd_write(sd, lconfig->ysize >> 1,
+ OSD_VIDWIN0YL);
+ }
} else {
osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP);
osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL);
+ if ((sd->vpbe_type == VPBE_VERSION_2) &&
+ lconfig->pixfmt == PIXFMT_NV12) {
+ osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP);
+ osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL);
+ }
}
break;
}
@@ -1089,6 +1466,11 @@ static void _osd_init(struct osd_state *sd)
osd_write(sd, 0, OSD_OSDWIN1MD);
osd_write(sd, 0, OSD_RECTCUR);
osd_write(sd, 0, OSD_MISCCTL);
+ if (sd->vpbe_type == VPBE_VERSION_3) {
+ osd_write(sd, 0, OSD_VBNDRY);
+ osd_write(sd, 0, OSD_EXTMODE);
+ osd_write(sd, OSD_MISCCTL_DMANG, OSD_MISCCTL);
+ }
}
static void osd_set_left_margin(struct osd_state *sd, u32 val)
@@ -1110,6 +1492,14 @@ static int osd_initialize(struct osd_state *osd)
/* set default Cb/Cr order */
osd->yc_pixfmt = PIXFMT_YCbCrI;
+ if (osd->vpbe_type == VPBE_VERSION_3) {
+ /*
+ * ROM CLUT1 on the DM355 is similar (identical?) to ROM CLUT0
+ * on the DM6446, so make ROM_CLUT1 the default on the DM355.
+ */
+ osd->rom_clut = ROM_CLUT1;
+ }
+
_osd_set_field_inversion(osd, osd->field_inversion);
_osd_set_rom_clut(osd, osd->rom_clut);
@@ -1208,23 +1598,7 @@ static struct platform_driver osd_driver = {
},
};
-static int osd_init(void)
-{
- if (platform_driver_register(&osd_driver)) {
- printk(KERN_ERR "Unable to register davinci osd driver\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void osd_exit(void)
-{
- platform_driver_unregister(&osd_driver);
-}
-
-module_init(osd_init);
-module_exit(osd_exit);
+module_platform_driver(osd_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DaVinci OSD Manager Driver");
diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c
index 03a3e5c65ee7..b21ecc8d134d 100644
--- a/drivers/media/video/davinci/vpbe_venc.c
+++ b/drivers/media/video/davinci/vpbe_venc.c
@@ -27,7 +27,6 @@
#include <mach/hardware.h>
#include <mach/mux.h>
-#include <mach/io.h>
#include <mach/i2c.h>
#include <linux/io.h>
@@ -99,6 +98,8 @@ static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val)
return val;
}
+#define VDAC_COMPONENT 0x543
+#define VDAC_S_VIDEO 0x210
/* This function sets the dac of the VPBE for various outputs
*/
static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
@@ -109,11 +110,12 @@ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
venc_write(sd, VENC_DACSEL, 0);
break;
case 1:
- v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n");
- venc_write(sd, VENC_DACSEL, 0x210);
+ v4l2_dbg(debug, 1, sd, "Setting output to Component\n");
+ venc_write(sd, VENC_DACSEL, VDAC_COMPONENT);
break;
- case 2:
- venc_write(sd, VENC_DACSEL, 0x543);
+ case 2:
+ v4l2_dbg(debug, 1, sd, "Setting output to S-video\n");
+ venc_write(sd, VENC_DACSEL, VDAC_S_VIDEO);
break;
default:
return -EINVAL;
@@ -124,6 +126,8 @@ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
{
+ struct venc_state *venc = to_state(sd);
+ struct venc_platform_data *pdata = venc->pdata;
v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n");
if (benable) {
@@ -155,7 +159,8 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
/* Disable LCD output control (accepting default polarity) */
venc_write(sd, VENC_LCDOUT, 0);
- venc_write(sd, VENC_CMPNT, 0x100);
+ if (pdata->venc_type != VPBE_VERSION_3)
+ venc_write(sd, VENC_CMPNT, 0x100);
venc_write(sd, VENC_HSPLS, 0);
venc_write(sd, VENC_HINT, 0);
venc_write(sd, VENC_HSTART, 0);
@@ -178,11 +183,14 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
}
}
+#define VDAC_CONFIG_SD_V3 0x0E21A6B6
+#define VDAC_CONFIG_SD_V2 0x081141CF
/*
* setting NTSC mode
*/
static int venc_set_ntsc(struct v4l2_subdev *sd)
{
+ u32 val;
struct venc_state *venc = to_state(sd);
struct venc_platform_data *pdata = venc->pdata;
@@ -195,12 +203,22 @@ static int venc_set_ntsc(struct v4l2_subdev *sd)
venc_enabledigitaloutput(sd, 0);
- /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
- venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
- /* Set REC656 Mode */
- venc_write(sd, VENC_YCCCTL, 0x1);
- venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ);
- venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS);
+ if (pdata->venc_type == VPBE_VERSION_3) {
+ venc_write(sd, VENC_CLKCTL, 0x01);
+ venc_write(sd, VENC_VIDCTL, 0);
+ val = vdaccfg_write(sd, VDAC_CONFIG_SD_V3);
+ } else if (pdata->venc_type == VPBE_VERSION_2) {
+ venc_write(sd, VENC_CLKCTL, 0x01);
+ venc_write(sd, VENC_VIDCTL, 0);
+ vdaccfg_write(sd, VDAC_CONFIG_SD_V2);
+ } else {
+ /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
+ venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
+ /* Set REC656 Mode */
+ venc_write(sd, VENC_YCCCTL, 0x1);
+ venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ);
+ venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS);
+ }
venc_write(sd, VENC_VMOD, 0);
venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
@@ -220,6 +238,7 @@ static int venc_set_ntsc(struct v4l2_subdev *sd)
static int venc_set_pal(struct v4l2_subdev *sd)
{
struct venc_state *venc = to_state(sd);
+ struct venc_platform_data *pdata = venc->pdata;
v4l2_dbg(debug, 2, sd, "venc_set_pal\n");
@@ -230,10 +249,20 @@ static int venc_set_pal(struct v4l2_subdev *sd)
venc_enabledigitaloutput(sd, 0);
- /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
- venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
- /* Set REC656 Mode */
- venc_write(sd, VENC_YCCCTL, 0x1);
+ if (pdata->venc_type == VPBE_VERSION_3) {
+ venc_write(sd, VENC_CLKCTL, 0x1);
+ venc_write(sd, VENC_VIDCTL, 0);
+ vdaccfg_write(sd, VDAC_CONFIG_SD_V3);
+ } else if (pdata->venc_type == VPBE_VERSION_2) {
+ venc_write(sd, VENC_CLKCTL, 0x1);
+ venc_write(sd, VENC_VIDCTL, 0);
+ vdaccfg_write(sd, VDAC_CONFIG_SD_V2);
+ } else {
+ /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
+ venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
+ /* Set REC656 Mode */
+ venc_write(sd, VENC_YCCCTL, 0x1);
+ }
venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT,
VENC_SYNCCTL_OVD);
@@ -252,6 +281,7 @@ static int venc_set_pal(struct v4l2_subdev *sd)
return 0;
}
+#define VDAC_CONFIG_HD_V2 0x081141EF
/*
* venc_set_480p59_94
*
@@ -263,6 +293,9 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd)
struct venc_platform_data *pdata = venc->pdata;
v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n");
+ if ((pdata->venc_type != VPBE_VERSION_1) &&
+ (pdata->venc_type != VPBE_VERSION_2))
+ return -EINVAL;
/* Setup clock at VPSS & VENC for SD */
if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0)
@@ -270,12 +303,18 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd)
venc_enabledigitaloutput(sd, 0);
+ if (pdata->venc_type == VPBE_VERSION_2)
+ vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
venc_write(sd, VENC_OSDCLK0, 0);
venc_write(sd, VENC_OSDCLK1, 1);
- venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
- VENC_VDPRO_DAFRQ);
- venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
- VENC_VDPRO_DAUPS);
+
+ if (pdata->venc_type == VPBE_VERSION_1) {
+ venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
+ VENC_VDPRO_DAFRQ);
+ venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
+ VENC_VDPRO_DAUPS);
+ }
+
venc_write(sd, VENC_VMOD, 0);
venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
VENC_VMOD_VIE);
@@ -302,19 +341,27 @@ static int venc_set_576p50(struct v4l2_subdev *sd)
v4l2_dbg(debug, 2, sd, "venc_set_576p50\n");
+ if ((pdata->venc_type != VPBE_VERSION_1) &&
+ (pdata->venc_type != VPBE_VERSION_2))
+ return -EINVAL;
/* Setup clock at VPSS & VENC for SD */
if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0)
return -EINVAL;
venc_enabledigitaloutput(sd, 0);
+ if (pdata->venc_type == VPBE_VERSION_2)
+ vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
+
venc_write(sd, VENC_OSDCLK0, 0);
venc_write(sd, VENC_OSDCLK1, 1);
- venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
- VENC_VDPRO_DAFRQ);
- venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
- VENC_VDPRO_DAUPS);
+ if (pdata->venc_type == VPBE_VERSION_1) {
+ venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
+ VENC_VDPRO_DAFRQ);
+ venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
+ VENC_VDPRO_DAUPS);
+ }
venc_write(sd, VENC_VMOD, 0);
venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
@@ -330,6 +377,63 @@ static int venc_set_576p50(struct v4l2_subdev *sd)
return 0;
}
+/*
+ * venc_set_720p60_internal - Setup 720p60 in venc for dm365 only
+ */
+static int venc_set_720p60_internal(struct v4l2_subdev *sd)
+{
+ struct venc_state *venc = to_state(sd);
+ struct venc_platform_data *pdata = venc->pdata;
+
+ if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_720P60) < 0)
+ return -EINVAL;
+
+ venc_enabledigitaloutput(sd, 0);
+
+ venc_write(sd, VENC_OSDCLK0, 0);
+ venc_write(sd, VENC_OSDCLK1, 1);
+
+ venc_write(sd, VENC_VMOD, 0);
+ /* DM365 component HD mode */
+ venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+ VENC_VMOD_VIE);
+ venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+ venc_modify(sd, VENC_VMOD, (HDTV_720P << VENC_VMOD_TVTYP_SHIFT),
+ VENC_VMOD_TVTYP);
+ venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+ venc_write(sd, VENC_XHINTVL, 0);
+ return 0;
+}
+
+/*
+ * venc_set_1080i30_internal - Setup 1080i30 in venc for dm365 only
+ */
+static int venc_set_1080i30_internal(struct v4l2_subdev *sd)
+{
+ struct venc_state *venc = to_state(sd);
+ struct venc_platform_data *pdata = venc->pdata;
+
+ if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_1080P30) < 0)
+ return -EINVAL;
+
+ venc_enabledigitaloutput(sd, 0);
+
+ venc_write(sd, VENC_OSDCLK0, 0);
+ venc_write(sd, VENC_OSDCLK1, 1);
+
+
+ venc_write(sd, VENC_VMOD, 0);
+ /* DM365 component HD mode */
+ venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+ VENC_VMOD_VIE);
+ venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+ venc_modify(sd, VENC_VMOD, (HDTV_1080I << VENC_VMOD_TVTYP_SHIFT),
+ VENC_VMOD_TVTYP);
+ venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+ venc_write(sd, VENC_XHINTVL, 0);
+ return 0;
+}
+
static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
{
v4l2_dbg(debug, 1, sd, "venc_s_std_output\n");
@@ -345,13 +449,30 @@ static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
static int venc_s_dv_preset(struct v4l2_subdev *sd,
struct v4l2_dv_preset *dv_preset)
{
+ struct venc_state *venc = to_state(sd);
+ int ret;
+
v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n");
if (dv_preset->preset == V4L2_DV_576P50)
return venc_set_576p50(sd);
else if (dv_preset->preset == V4L2_DV_480P59_94)
return venc_set_480p59_94(sd);
-
+ else if ((dv_preset->preset == V4L2_DV_720P60) &&
+ (venc->pdata->venc_type == VPBE_VERSION_2)) {
+ /* TBD setup internal 720p mode here */
+ ret = venc_set_720p60_internal(sd);
+ /* for DM365 VPBE, there is DAC inside */
+ vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
+ return ret;
+ } else if ((dv_preset->preset == V4L2_DV_1080I30) &&
+ (venc->pdata->venc_type == VPBE_VERSION_2)) {
+ /* TBD setup internal 1080i mode here */
+ ret = venc_set_1080i30_internal(sd);
+ /* for DM365 VPBE, there is DAC inside */
+ vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
+ return ret;
+ }
return -EINVAL;
}
@@ -508,11 +629,41 @@ static int venc_probe(struct platform_device *pdev)
goto release_venc_mem_region;
}
+ if (venc->pdata->venc_type != VPBE_VERSION_1) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(venc->pdev,
+ "Unable to get VDAC_CONFIG address map\n");
+ ret = -ENODEV;
+ goto unmap_venc_io;
+ }
+
+ if (!request_mem_region(res->start,
+ resource_size(res), "venc")) {
+ dev_err(venc->pdev,
+ "Unable to reserve VDAC_CONFIG MMIO region\n");
+ ret = -ENODEV;
+ goto unmap_venc_io;
+ }
+
+ venc->vdaccfg_reg = ioremap_nocache(res->start,
+ resource_size(res));
+ if (!venc->vdaccfg_reg) {
+ dev_err(venc->pdev,
+ "Unable to map VDAC_CONFIG IO space\n");
+ ret = -ENODEV;
+ goto release_vdaccfg_mem_region;
+ }
+ }
spin_lock_init(&venc->lock);
platform_set_drvdata(pdev, venc);
dev_notice(venc->pdev, "VENC sub device probe success\n");
return 0;
+release_vdaccfg_mem_region:
+ release_mem_region(res->start, resource_size(res));
+unmap_venc_io:
+ iounmap(venc->venc_base);
release_venc_mem_region:
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
@@ -529,6 +680,11 @@ static int venc_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
iounmap((void *)venc->venc_base);
release_mem_region(res->start, resource_size(res));
+ if (venc->pdata->venc_type != VPBE_VERSION_1) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ iounmap((void *)venc->vdaccfg_reg);
+ release_mem_region(res->start, resource_size(res));
+ }
kfree(venc);
return 0;
@@ -543,23 +699,7 @@ static struct platform_driver venc_driver = {
},
};
-static int venc_init(void)
-{
- if (platform_driver_register(&venc_driver)) {
- printk(KERN_ERR "Unable to register venc driver\n");
- return -ENODEV;
- }
- return 0;
-}
-
-static void venc_exit(void)
-{
- platform_driver_unregister(&venc_driver);
- return;
-}
-
-module_init(venc_init);
-module_exit(venc_exit);
+module_platform_driver(venc_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("VPBE VENC Driver");
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index 5b38fc93ff28..20cf271a774b 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -2076,20 +2076,4 @@ static struct platform_driver vpfe_driver = {
.remove = __devexit_p(vpfe_remove),
};
-static __init int vpfe_init(void)
-{
- printk(KERN_NOTICE "vpfe_init\n");
- /* Register driver to the kernel */
- return platform_driver_register(&vpfe_driver);
-}
-
-/*
- * vpfe_cleanup : This function un-registers device driver
- */
-static void vpfe_cleanup(void)
-{
- platform_driver_unregister(&vpfe_driver);
-}
-
-module_init(vpfe_init);
-module_exit(vpfe_cleanup);
+module_platform_driver(vpfe_driver);
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h
index 25036cb11bea..8bcac65f9294 100644
--- a/drivers/media/video/davinci/vpif.h
+++ b/drivers/media/video/davinci/vpif.h
@@ -18,8 +18,6 @@
#include <linux/io.h>
#include <linux/videodev2.h>
-#include <mach/hardware.h>
-#include <mach/dm646x.h>
#include <media/davinci/vpif_types.h>
/* Maximum channel allowed */
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
index 49e4deb50043..6504e40a31dd 100644
--- a/drivers/media/video/davinci/vpif_capture.c
+++ b/drivers/media/video/davinci/vpif_capture.c
@@ -2177,6 +2177,12 @@ static __init int vpif_probe(struct platform_device *pdev)
return err;
}
+ err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
+ if (err) {
+ v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");
+ return err;
+ }
+
k = 0;
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) {
for (i = res->start; i <= res->end; i++) {
@@ -2246,12 +2252,6 @@ static __init int vpif_probe(struct platform_device *pdev)
goto probe_out;
}
- err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
- if (err) {
- v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");
- goto probe_subdev_out;
- }
-
for (i = 0; i < subdev_count; i++) {
subdevdata = &config->subdev_info[i];
vpif_obj.sd[i] =
@@ -2281,7 +2281,6 @@ probe_subdev_out:
j = VPIF_CAPTURE_MAX_DEVICES;
probe_out:
- v4l2_device_unregister(&vpif_obj.v4l2_dev);
for (k = 0; k < j; k++) {
/* Get the pointer to the channel object */
ch = vpif_obj.dev[k];
@@ -2303,6 +2302,7 @@ vpif_int_err:
if (res)
i = res->end;
}
+ v4l2_device_unregister(&vpif_obj.v4l2_dev);
return err;
}
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index 286f02910044..7fa34b4fae26 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -39,8 +39,6 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-chip-ident.h>
-#include <mach/dm646x.h>
-
#include "vpif_display.h"
#include "vpif.h"
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index cff0768afbf5..e2a7b77c39c7 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -193,7 +193,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
urb->dev = dev->udev;
urb->context = dev;
- urb->pipe = usb_rcvisocpipe(dev->udev, 0x83);
+ urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = dev->adev.transfer_buffer[i];
urb->interval = 1;
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 93807dcf944e..9fd8cc7dbb23 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -336,6 +336,61 @@ static struct em28xx_reg_seq pctv_460e[] = {
{ -1, -1, -1, -1},
};
+#if 0
+static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
+ {EM2874_R80_GPIO, 0x6f, 0xff, 10},
+ {EM2874_R80_GPIO, 0x4f, 0xff, 10}, /* xc5000 reset */
+ {EM2874_R80_GPIO, 0x6f, 0xff, 10},
+ {EM2874_R80_GPIO, 0x4f, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq hauppauge_930c_digital[] = {
+ {EM2874_R80_GPIO, 0xf6, 0xff, 10},
+ {EM2874_R80_GPIO, 0xe6, 0xff, 100},
+ {EM2874_R80_GPIO, 0xa6, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+#endif
+
+/* 1b80:e425 MaxMedia UB425-TC
+ * GPIO_6 - demod reset, 0=active
+ * GPIO_7 - LED, 0=active
+ */
+static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
+ {EM2874_R80_GPIO, 0x83, 0xff, 100},
+ {EM2874_R80_GPIO, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */
+ {EM2874_R80_GPIO, 0x43, 0xff, 000}, /* GPIO_7 = 0 */
+ {-1, -1, -1, -1},
+};
+
+/* 2304:0242 PCTV QuatroStick (510e)
+ * GPIO_2: decoder reset, 0=active
+ * GPIO_4: decoder suspend, 0=active
+ * GPIO_6: demod reset, 0=active
+ * GPIO_7: LED, 1=active
+ */
+static struct em28xx_reg_seq pctv_510e[] = {
+ {EM2874_R80_GPIO, 0x10, 0xff, 100},
+ {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+ {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+ { -1, -1, -1, -1},
+};
+
+/* 2013:0251 PCTV QuatroStick nano (520e)
+ * GPIO_2: decoder reset, 0=active
+ * GPIO_4: decoder suspend, 0=active
+ * GPIO_6: demod reset, 0=active
+ * GPIO_7: LED, 1=active
+ */
+static struct em28xx_reg_seq pctv_520e[] = {
+ {EM2874_R80_GPIO, 0x10, 0xff, 100},
+ {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+ {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+ {EM2874_R80_GPIO, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
+ { -1, -1, -1, -1},
+};
+
/*
* Board definitions
*/
@@ -839,6 +894,10 @@ struct em28xx_board em28xx_boards[] = {
[EM2870_BOARD_KWORLD_355U] = {
.name = "Kworld 355 U DVB-T",
.valid = EM28XX_BOARD_NOT_VALIDATED,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = default_tuner_gpio,
+ .has_dvb = 1,
+ .dvb_gpio = default_digital,
},
[EM2870_BOARD_PINNACLE_PCTV_DVB] = {
.name = "Pinnacle PCTV DVB-T",
@@ -887,6 +946,37 @@ struct em28xx_board em28xx_boards[] = {
.tuner_addr = 0x41,
.dvb_gpio = terratec_h5_digital, /* FIXME: probably wrong */
.tuner_gpio = terratec_h5_gpio,
+#else
+ .tuner_type = TUNER_ABSENT,
+#endif
+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
+ },
+ [EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C] = {
+ .name = "Hauppauge WinTV HVR 930C",
+ .has_dvb = 1,
+#if 0 /* FIXME: Add analog support */
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x41,
+ .dvb_gpio = hauppauge_930c_digital,
+ .tuner_gpio = hauppauge_930c_gpio,
+#else
+ .tuner_type = TUNER_ABSENT,
+#endif
+ .ir_codes = RC_MAP_HAUPPAUGE,
+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
+ },
+ [EM2884_BOARD_CINERGY_HTC_STICK] = {
+ .name = "Terratec Cinergy HTC Stick",
+ .has_dvb = 1,
+#if 0
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .tuner_addr = 0x41,
+ .dvb_gpio = terratec_h5_digital, /* FIXME: probably wrong */
+ .tuner_gpio = terratec_h5_gpio,
#endif
.i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
EM28XX_I2C_CLK_WAIT_ENABLE |
@@ -1127,7 +1217,7 @@ struct em28xx_board em28xx_boards[] = {
.name = "Terratec Cinergy 200 USB",
.is_em2800 = 1,
.has_ir_i2c = 1,
- .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tuner_type = TUNER_LG_TALN,
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_SAA711X,
.input = { {
@@ -1218,7 +1308,7 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2820_BOARD_PINNACLE_DVC_90] = {
.name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker "
- "/ Kworld DVD Maker 2",
+ "/ Kworld DVD Maker 2 / Plextor ConvertX PX-AV100U",
.tuner_type = TUNER_ABSENT, /* capture only board */
.decoder = EM28XX_SAA711X,
.input = { {
@@ -1840,6 +1930,57 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
},
+ /* eb1a:5006 Honestech VIDBOX NW03
+ * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner */
+ [EM2860_BOARD_HT_VIDBOX_NW03] = {
+ .name = "Honestech Vidbox NW03",
+ .tuner_type = TUNER_ABSENT,
+ .decoder = EM28XX_SAA711X,
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_LINE_IN,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = SAA7115_SVIDEO3, /* S-VIDEO needs confirming */
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
+ },
+ /* 1b80:e425 MaxMedia UB425-TC
+ * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */
+ [EM2874_BOARD_MAXMEDIA_UB425_TC] = {
+ .name = "MaxMedia UB425-TC",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = maxmedia_ub425_tc,
+ .has_dvb = 1,
+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
+ },
+ /* 2304:0242 PCTV QuatroStick (510e)
+ * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+ [EM2884_BOARD_PCTV_510E] = {
+ .name = "PCTV QuatroStick (510e)",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = pctv_510e,
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
+ },
+ /* 2013:0251 PCTV QuatroStick nano (520e)
+ * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+ [EM2884_BOARD_PCTV_520E] = {
+ .name = "PCTV QuatroStick nano (520e)",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = pctv_520e,
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
+ },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1899,6 +2040,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2800_BOARD_GRABBEEX_USB2800 },
{ USB_DEVICE(0xeb1a, 0xe357),
.driver_info = EM2870_BOARD_KWORLD_355U },
+ { USB_DEVICE(0xeb1a, 0xe359),
+ .driver_info = EM2870_BOARD_KWORLD_355U },
{ USB_DEVICE(0x1b80, 0xe302),
.driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */
{ USB_DEVICE(0x1b80, 0xe304),
@@ -1914,17 +2057,23 @@ struct usb_device_id em28xx_id_table[] = {
{ USB_DEVICE(0x0ccd, 0x0042),
.driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
{ USB_DEVICE(0x0ccd, 0x0043),
+ .driver_info = EM2870_BOARD_TERRATEC_XS },
+ { USB_DEVICE(0x0ccd, 0x008e), /* Cinergy HTC USB XS Rev. 1 */
+ .driver_info = EM2884_BOARD_TERRATEC_H5 },
+ { USB_DEVICE(0x0ccd, 0x00ac), /* Cinergy HTC USB XS Rev. 2 */
+ .driver_info = EM2884_BOARD_TERRATEC_H5 },
+ { USB_DEVICE(0x0ccd, 0x10a2), /* H5 Rev. 1 */
.driver_info = EM2884_BOARD_TERRATEC_H5 },
- { USB_DEVICE(0x0ccd, 0x10a2), /* Rev. 1 */
+ { USB_DEVICE(0x0ccd, 0x10ad), /* H5 Rev. 2 */
.driver_info = EM2884_BOARD_TERRATEC_H5 },
- { USB_DEVICE(0x0ccd, 0x10ad), /* Rev. 2 */
- .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
{ USB_DEVICE(0x0ccd, 0x0084),
.driver_info = EM2860_BOARD_TERRATEC_AV350 },
{ USB_DEVICE(0x0ccd, 0x0096),
.driver_info = EM2860_BOARD_TERRATEC_GRABBY },
{ USB_DEVICE(0x0ccd, 0x10AF),
.driver_info = EM2860_BOARD_TERRATEC_GRABBY },
+ { USB_DEVICE(0x0ccd, 0x00b2),
+ .driver_info = EM2884_BOARD_CINERGY_HTC_STICK },
{ USB_DEVICE(0x0fd9, 0x0033),
.driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE},
{ USB_DEVICE(0x185b, 0x2870),
@@ -1963,6 +2112,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
{ USB_DEVICE(0x0413, 0x6023),
.driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
+ { USB_DEVICE(0x093b, 0xa003),
+ .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
{ USB_DEVICE(0x093b, 0xa005),
.driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U },
{ USB_DEVICE(0x04bb, 0x0515),
@@ -1975,6 +2126,18 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM28174_BOARD_PCTV_290E },
{ USB_DEVICE(0x2013, 0x024c),
.driver_info = EM28174_BOARD_PCTV_460E },
+ { USB_DEVICE(0x2040, 0x1605),
+ .driver_info = EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C },
+ { USB_DEVICE(0xeb1a, 0x5006),
+ .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 },
+ { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */
+ .driver_info = EM2860_BOARD_EASYCAP },
+ { USB_DEVICE(0x1b80, 0xe425),
+ .driver_info = EM2874_BOARD_MAXMEDIA_UB425_TC },
+ { USB_DEVICE(0x2304, 0x0242),
+ .driver_info = EM2884_BOARD_PCTV_510E },
+ { USB_DEVICE(0x2013, 0x0251),
+ .driver_info = EM2884_BOARD_PCTV_520E },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2028,10 +2191,10 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
int rc = 0;
struct em28xx *dev = ptr;
- if (dev->tuner_type != TUNER_XC2028)
+ if (dev->tuner_type != TUNER_XC2028 && dev->tuner_type != TUNER_XC5000)
return 0;
- if (command != XC2028_TUNER_RESET)
+ if (command != XC2028_TUNER_RESET && command != XC5000_TUNER_RESET)
return 0;
rc = em28xx_gpio_set(dev, dev->board.tuner_gpio);
@@ -2203,7 +2366,8 @@ void em28xx_pre_card_setup(struct em28xx *dev)
/* Set the initial XCLK and I2C clock values based on the board
definition */
em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f);
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
+ if (!dev->board.is_em2800)
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
msleep(50);
/* request some modules */
@@ -2832,11 +2996,10 @@ void em28xx_release_resources(struct em28xx *dev)
* em28xx_init_dev()
* allocates and inits the device structs, registers i2c bus and v4l device
*/
-static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
struct usb_interface *interface,
int minor)
{
- struct em28xx *dev = *devhandle;
int retval;
dev->udev = udev;
@@ -2931,7 +3094,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
if (!dev->board.is_em2800) {
/* Resets I2C speed */
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
+ retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
if (retval < 0) {
em28xx_errdev("%s: em28xx_write_reg failed!"
" retval [%d]\n",
@@ -3031,15 +3194,13 @@ unregister_dev:
static int em28xx_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
- const struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev;
struct em28xx *dev = NULL;
int retval;
- bool is_audio_only = false, has_audio = false;
- int i, nr, isoc_pipe;
+ bool has_audio = false, has_video = false, has_dvb = false;
+ int i, nr;
const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
char *speed;
- char descr[255] = "";
udev = usb_get_dev(interface_to_usbdev(interface));
@@ -3068,54 +3229,65 @@ static int em28xx_usb_probe(struct usb_interface *interface,
goto err;
}
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ em28xx_err(DRIVER_NAME ": out of memory!\n");
+ retval = -ENOMEM;
+ goto err;
+ }
+
+ /* compute alternate max packet sizes */
+ dev->alt_max_pkt_size = kmalloc(sizeof(dev->alt_max_pkt_size[0]) *
+ interface->num_altsetting, GFP_KERNEL);
+ if (dev->alt_max_pkt_size == NULL) {
+ em28xx_errdev("out of memory!\n");
+ kfree(dev);
+ retval = -ENOMEM;
+ goto err;
+ }
+
/* Get endpoints */
for (i = 0; i < interface->num_altsetting; i++) {
int ep;
for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
- struct usb_host_endpoint *e;
- e = &interface->altsetting[i].endpoint[ep];
-
- if (e->desc.bEndpointAddress == 0x83)
- has_audio = true;
+ const struct usb_endpoint_descriptor *e;
+ int sizedescr, size;
+
+ e = &interface->altsetting[i].endpoint[ep].desc;
+
+ sizedescr = le16_to_cpu(e->wMaxPacketSize);
+ size = sizedescr & 0x7ff;
+
+ if (udev->speed == USB_SPEED_HIGH)
+ size = size * hb_mult(sizedescr);
+
+ if (usb_endpoint_xfer_isoc(e) &&
+ usb_endpoint_dir_in(e)) {
+ switch (e->bEndpointAddress) {
+ case EM28XX_EP_AUDIO:
+ has_audio = true;
+ break;
+ case EM28XX_EP_ANALOG:
+ has_video = true;
+ dev->alt_max_pkt_size[i] = size;
+ break;
+ case EM28XX_EP_DIGITAL:
+ has_dvb = true;
+ if (size > dev->dvb_max_pkt_size) {
+ dev->dvb_max_pkt_size = size;
+ dev->dvb_alt = i;
+ }
+ break;
+ }
+ }
}
}
- endpoint = &interface->cur_altsetting->endpoint[0].desc;
-
- /* check if the device has the iso in endpoint at the correct place */
- if (usb_endpoint_xfer_isoc(endpoint)
- &&
- (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) {
- /* It's a newer em2874/em2875 device */
- isoc_pipe = 0;
- } else {
- int check_interface = 1;
- isoc_pipe = 1;
- endpoint = &interface->cur_altsetting->endpoint[1].desc;
- if (!usb_endpoint_xfer_isoc(endpoint))
- check_interface = 0;
-
- if (usb_endpoint_dir_out(endpoint))
- check_interface = 0;
-
- if (!check_interface) {
- if (has_audio) {
- is_audio_only = true;
- } else {
- em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
- "interface %i, class %i found.\n",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct),
- ifnum,
- interface->altsetting[0].desc.bInterfaceClass);
- em28xx_err(DRIVER_NAME " This is an anciliary "
- "interface not used by the driver\n");
-
- retval = -ENODEV;
- goto err;
- }
- }
+ if (!(has_audio || has_video || has_dvb)) {
+ retval = -ENODEV;
+ goto err_free;
}
switch (udev->speed) {
@@ -3133,20 +3305,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
speed = "unknown";
}
- if (udev->manufacturer)
- strlcpy(descr, udev->manufacturer, sizeof(descr));
-
- if (udev->product) {
- if (*descr)
- strlcat(descr, " ", sizeof(descr));
- strlcat(descr, udev->product, sizeof(descr));
- }
- if (*descr)
- strlcat(descr, " ", sizeof(descr));
-
printk(KERN_INFO DRIVER_NAME
- ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n",
- descr,
+ ": New device %s %s @ %s Mbps "
+ "(%04x:%04x, interface %d, class %d)\n",
+ udev->manufacturer ? udev->manufacturer : "",
+ udev->product ? udev->product : "",
speed,
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct),
@@ -3157,6 +3320,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
printk(KERN_INFO DRIVER_NAME
": Audio Vendor Class interface %i found\n",
ifnum);
+ if (has_video)
+ printk(KERN_INFO DRIVER_NAME
+ ": Video interface %i found\n",
+ ifnum);
+ if (has_dvb)
+ printk(KERN_INFO DRIVER_NAME
+ ": DVB interface %i found\n",
+ ifnum);
/*
* Make sure we have 480 Mbps of bandwidth, otherwise things like
@@ -3168,22 +3339,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
printk(DRIVER_NAME ": Device must be connected to a high-speed"
" USB 2.0 port.\n");
retval = -ENODEV;
- goto err;
- }
-
- /* allocate memory for our device state and initialize it */
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- em28xx_err(DRIVER_NAME ": out of memory!\n");
- retval = -ENOMEM;
- goto err;
+ goto err_free;
}
snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr);
dev->devno = nr;
dev->model = id->driver_info;
dev->alt = -1;
- dev->is_audio_only = is_audio_only;
+ dev->is_audio_only = has_audio && !(has_video || has_dvb);
dev->has_alsa_audio = has_audio;
dev->audio_ifnum = ifnum;
@@ -3196,26 +3359,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
}
}
- /* compute alternate max packet sizes */
dev->num_alt = interface->num_altsetting;
- dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
-
- if (dev->alt_max_pkt_size == NULL) {
- em28xx_errdev("out of memory!\n");
- kfree(dev);
- retval = -ENOMEM;
- goto err;
- }
-
- for (i = 0; i < dev->num_alt ; i++) {
- u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
- unsigned int size = tmp & 0x7ff;
-
- if (udev->speed == USB_SPEED_HIGH)
- size = size * hb_mult(tmp);
-
- dev->alt_max_pkt_size[i] = size;
- }
if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
dev->model = card[nr];
@@ -3226,12 +3370,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* allocate device struct */
mutex_init(&dev->lock);
mutex_lock(&dev->lock);
- retval = em28xx_init_dev(&dev, udev, interface, nr);
+ retval = em28xx_init_dev(dev, udev, interface, nr);
if (retval) {
- mutex_unlock(&dev->lock);
- kfree(dev->alt_max_pkt_size);
- kfree(dev);
- goto err;
+ goto unlock_and_free;
+ }
+
+ if (has_dvb) {
+ /* pre-allocate DVB isoc transfer buffers */
+ retval = em28xx_alloc_isoc(dev, EM28XX_DIGITAL_MODE,
+ EM28XX_DVB_MAX_PACKETS,
+ EM28XX_DVB_NUM_BUFS,
+ dev->dvb_max_pkt_size);
+ if (retval) {
+ goto unlock_and_free;
+ }
}
request_modules(dev);
@@ -3250,6 +3402,13 @@ static int em28xx_usb_probe(struct usb_interface *interface,
return 0;
+unlock_and_free:
+ mutex_unlock(&dev->lock);
+
+err_free:
+ kfree(dev->alt_max_pkt_size);
+ kfree(dev);
+
err:
clear_bit(nr, &em28xx_devused);
@@ -3299,7 +3458,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
video_device_node_name(dev->vdev));
dev->state |= DEV_MISCONFIGURED;
- em28xx_uninit_isoc(dev);
+ em28xx_uninit_isoc(dev, dev->mode);
dev->state |= DEV_DISCONNECTED;
wake_up_interruptible(&dev->wait_frame);
wake_up_interruptible(&dev->wait_stream);
@@ -3308,6 +3467,9 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
em28xx_release_resources(dev);
}
+ /* free DVB isoc buffers */
+ em28xx_uninit_isoc(dev, EM28XX_DIGITAL_MODE);
+
mutex_unlock(&dev->lock);
em28xx_close_extension(dev);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 804a4ab47ac6..53a9fb91e97e 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -568,7 +568,7 @@ int em28xx_audio_setup(struct em28xx *dev)
em28xx_warn("AC97 features = 0x%04x\n", feat);
/* Try to identify what audio processor we have */
- if ((vid == 0xffffffff) && (feat == 0x6a90))
+ if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90))
dev->audio_mode.ac97 = EM28XX_AC97_EM202;
else if ((vid >> 8) == 0x838476)
dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL;
@@ -666,6 +666,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
return rc;
}
+EXPORT_SYMBOL_GPL(em28xx_capture_start);
int em28xx_vbi_supported(struct em28xx *dev)
{
@@ -961,145 +962,192 @@ static void em28xx_irq_callback(struct urb *urb)
/*
* Stop and Deallocate URBs
*/
-void em28xx_uninit_isoc(struct em28xx *dev)
+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode)
{
struct urb *urb;
+ struct em28xx_usb_isoc_bufs *isoc_bufs;
int i;
- em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
+ em28xx_isocdbg("em28xx: called em28xx_uninit_isoc in mode %d\n", mode);
+
+ if (mode == EM28XX_DIGITAL_MODE)
+ isoc_bufs = &dev->isoc_ctl.digital_bufs;
+ else
+ isoc_bufs = &dev->isoc_ctl.analog_bufs;
dev->isoc_ctl.nfields = -1;
- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- urb = dev->isoc_ctl.urb[i];
+ for (i = 0; i < isoc_bufs->num_bufs; i++) {
+ urb = isoc_bufs->urb[i];
if (urb) {
if (!irqs_disabled())
usb_kill_urb(urb);
else
usb_unlink_urb(urb);
- if (dev->isoc_ctl.transfer_buffer[i]) {
+ if (isoc_bufs->transfer_buffer[i]) {
usb_free_coherent(dev->udev,
urb->transfer_buffer_length,
- dev->isoc_ctl.transfer_buffer[i],
+ isoc_bufs->transfer_buffer[i],
urb->transfer_dma);
}
usb_free_urb(urb);
- dev->isoc_ctl.urb[i] = NULL;
+ isoc_bufs->urb[i] = NULL;
}
- dev->isoc_ctl.transfer_buffer[i] = NULL;
+ isoc_bufs->transfer_buffer[i] = NULL;
}
- kfree(dev->isoc_ctl.urb);
- kfree(dev->isoc_ctl.transfer_buffer);
+ kfree(isoc_bufs->urb);
+ kfree(isoc_bufs->transfer_buffer);
- dev->isoc_ctl.urb = NULL;
- dev->isoc_ctl.transfer_buffer = NULL;
- dev->isoc_ctl.num_bufs = 0;
+ isoc_bufs->urb = NULL;
+ isoc_bufs->transfer_buffer = NULL;
+ isoc_bufs->num_bufs = 0;
em28xx_capture_start(dev, 0);
}
EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
/*
- * Allocate URBs and start IRQ
+ * Allocate URBs
*/
-int em28xx_init_isoc(struct em28xx *dev, int max_packets,
- int num_bufs, int max_pkt_size,
- int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
+ int max_packets, int num_bufs, int max_pkt_size)
{
- struct em28xx_dmaqueue *dma_q = &dev->vidq;
- struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+ struct em28xx_usb_isoc_bufs *isoc_bufs;
int i;
int sb_size, pipe;
struct urb *urb;
int j, k;
- int rc;
- em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
+ em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode);
+
+ if (mode == EM28XX_DIGITAL_MODE)
+ isoc_bufs = &dev->isoc_ctl.digital_bufs;
+ else
+ isoc_bufs = &dev->isoc_ctl.analog_bufs;
/* De-allocates all pending stuff */
- em28xx_uninit_isoc(dev);
+ em28xx_uninit_isoc(dev, mode);
- dev->isoc_ctl.isoc_copy = isoc_copy;
- dev->isoc_ctl.num_bufs = num_bufs;
+ isoc_bufs->num_bufs = num_bufs;
- dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
- if (!dev->isoc_ctl.urb) {
+ isoc_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!isoc_bufs->urb) {
em28xx_errdev("cannot alloc memory for usb buffers\n");
return -ENOMEM;
}
- dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
- GFP_KERNEL);
- if (!dev->isoc_ctl.transfer_buffer) {
+ isoc_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+ GFP_KERNEL);
+ if (!isoc_bufs->transfer_buffer) {
em28xx_errdev("cannot allocate memory for usb transfer\n");
- kfree(dev->isoc_ctl.urb);
+ kfree(isoc_bufs->urb);
return -ENOMEM;
}
- dev->isoc_ctl.max_pkt_size = max_pkt_size;
+ isoc_bufs->max_pkt_size = max_pkt_size;
+ isoc_bufs->num_packets = max_packets;
dev->isoc_ctl.vid_buf = NULL;
dev->isoc_ctl.vbi_buf = NULL;
- sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+ sb_size = isoc_bufs->num_packets * isoc_bufs->max_pkt_size;
/* allocate urbs and transfer buffers */
- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+ for (i = 0; i < isoc_bufs->num_bufs; i++) {
+ urb = usb_alloc_urb(isoc_bufs->num_packets, GFP_KERNEL);
if (!urb) {
em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
- em28xx_uninit_isoc(dev);
+ em28xx_uninit_isoc(dev, mode);
return -ENOMEM;
}
- dev->isoc_ctl.urb[i] = urb;
+ isoc_bufs->urb[i] = urb;
- dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+ isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev,
sb_size, GFP_KERNEL, &urb->transfer_dma);
- if (!dev->isoc_ctl.transfer_buffer[i]) {
+ if (!isoc_bufs->transfer_buffer[i]) {
em28xx_err("unable to allocate %i bytes for transfer"
" buffer %i%s\n",
sb_size, i,
in_interrupt() ? " while in int" : "");
- em28xx_uninit_isoc(dev);
+ em28xx_uninit_isoc(dev, mode);
return -ENOMEM;
}
- memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+ memset(isoc_bufs->transfer_buffer[i], 0, sb_size);
/* FIXME: this is a hack - should be
'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
should also be using 'desc.bInterval'
*/
pipe = usb_rcvisocpipe(dev->udev,
- dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84);
+ mode == EM28XX_ANALOG_MODE ?
+ EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL);
usb_fill_int_urb(urb, dev->udev, pipe,
- dev->isoc_ctl.transfer_buffer[i], sb_size,
+ isoc_bufs->transfer_buffer[i], sb_size,
em28xx_irq_callback, dev, 1);
- urb->number_of_packets = max_packets;
+ urb->number_of_packets = isoc_bufs->num_packets;
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
k = 0;
- for (j = 0; j < max_packets; j++) {
+ for (j = 0; j < isoc_bufs->num_packets; j++) {
urb->iso_frame_desc[j].offset = k;
urb->iso_frame_desc[j].length =
- dev->isoc_ctl.max_pkt_size;
- k += dev->isoc_ctl.max_pkt_size;
+ isoc_bufs->max_pkt_size;
+ k += isoc_bufs->max_pkt_size;
}
}
+ return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_alloc_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
+ int max_packets, int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+{
+ struct em28xx_dmaqueue *dma_q = &dev->vidq;
+ struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+ struct em28xx_usb_isoc_bufs *isoc_bufs;
+ int i;
+ int rc;
+ int alloc;
+
+ em28xx_isocdbg("em28xx: called em28xx_init_isoc in mode %d\n", mode);
+
+ dev->isoc_ctl.isoc_copy = isoc_copy;
+
+ if (mode == EM28XX_DIGITAL_MODE) {
+ isoc_bufs = &dev->isoc_ctl.digital_bufs;
+ /* no need to free/alloc isoc buffers in digital mode */
+ alloc = 0;
+ } else {
+ isoc_bufs = &dev->isoc_ctl.analog_bufs;
+ alloc = 1;
+ }
+
+ if (alloc) {
+ rc = em28xx_alloc_isoc(dev, mode, max_packets,
+ num_bufs, max_pkt_size);
+ if (rc)
+ return rc;
+ }
+
init_waitqueue_head(&dma_q->wq);
init_waitqueue_head(&vbi_dma_q->wq);
em28xx_capture_start(dev, 1);
/* submit urbs and enables IRQ */
- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+ for (i = 0; i < isoc_bufs->num_bufs; i++) {
+ rc = usb_submit_urb(isoc_bufs->urb[i], GFP_ATOMIC);
if (rc) {
em28xx_err("submit of urb %i failed (error=%i)\n", i,
rc);
- em28xx_uninit_isoc(dev);
+ em28xx_uninit_isoc(dev, mode);
return rc;
}
}
@@ -1108,62 +1156,6 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
}
EXPORT_SYMBOL_GPL(em28xx_init_isoc);
-/* Determine the packet size for the DVB stream for the given device
- (underlying value programmed into the eeprom) */
-int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
-{
- unsigned int chip_cfg2;
- unsigned int packet_size;
-
- switch (dev->chip_id) {
- case CHIP_ID_EM2710:
- case CHIP_ID_EM2750:
- case CHIP_ID_EM2800:
- case CHIP_ID_EM2820:
- case CHIP_ID_EM2840:
- case CHIP_ID_EM2860:
- /* No DVB support */
- return -EINVAL;
- case CHIP_ID_EM2870:
- case CHIP_ID_EM2883:
- /* TS max packet size stored in bits 1-0 of R01 */
- chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2);
- switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) {
- case EM28XX_CHIPCFG2_TS_PACKETSIZE_188:
- packet_size = 188;
- break;
- case EM28XX_CHIPCFG2_TS_PACKETSIZE_376:
- packet_size = 376;
- break;
- case EM28XX_CHIPCFG2_TS_PACKETSIZE_564:
- packet_size = 564;
- break;
- case EM28XX_CHIPCFG2_TS_PACKETSIZE_752:
- packet_size = 752;
- break;
- }
- break;
- case CHIP_ID_EM2874:
- /*
- * FIXME: for now assumes 564 like it was before, but the
- * em2874 code should be added to return the proper value
- */
- packet_size = 564;
- break;
- case CHIP_ID_EM2884:
- case CHIP_ID_EM28174:
- default:
- /*
- * FIXME: same as em2874. 564 was enough for 22 Mbit DVB-T
- * but not enough for 44 Mbit DVB-C.
- */
- packet_size = 752;
- }
-
- return packet_size;
-}
-EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize);
-
/*
* em28xx_wake_i2c()
* configure i2c attached devices
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index cef7a2d409cb..503a8d5b5382 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -44,6 +44,7 @@
#include "drxk.h"
#include "tda10071.h"
#include "a8293.h"
+#include "qt1010.h"
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -60,9 +61,6 @@ if (debug >= level) \
printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
} while (0)
-#define EM28XX_DVB_NUM_BUFS 5
-#define EM28XX_DVB_MAX_PACKETS 64
-
struct em28xx_dvb {
struct dvb_frontend *fe[2];
@@ -163,28 +161,29 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
struct em28xx *dev = dvb->adapter.priv;
int max_dvb_packet_size;
- usb_set_interface(dev->udev, 0, 1);
+ usb_set_interface(dev->udev, 0, dev->dvb_alt);
rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
if (rc < 0)
return rc;
- max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
+ max_dvb_packet_size = dev->dvb_max_pkt_size;
if (max_dvb_packet_size < 0)
return max_dvb_packet_size;
- dprintk(1, "Using %d buffers each with %d bytes\n",
+ dprintk(1, "Using %d buffers each with %d x %d bytes\n",
EM28XX_DVB_NUM_BUFS,
+ EM28XX_DVB_MAX_PACKETS,
max_dvb_packet_size);
- return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
- EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
- em28xx_dvb_isoc_copy);
+ return em28xx_init_isoc(dev, EM28XX_DIGITAL_MODE,
+ EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS,
+ max_dvb_packet_size, em28xx_dvb_isoc_copy);
}
static int em28xx_stop_streaming(struct em28xx_dvb *dvb)
{
struct em28xx *dev = dvb->adapter.priv;
- em28xx_uninit_isoc(dev);
+ em28xx_capture_start(dev, 0);
em28xx_set_mode(dev, EM28XX_SUSPEND);
@@ -302,10 +301,12 @@ static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
};
static struct drxd_config em28xx_drxd = {
- .index = 0, .demod_address = 0x70, .demod_revision = 0xa2,
- .demoda_address = 0x00, .pll_address = 0x00,
- .pll_type = DRXD_PLL_NONE, .clock = 12000, .insert_rs_byte = 1,
- .pll_set = NULL, .osc_deviation = NULL, .IF = 42800000,
+ .demod_address = 0x70,
+ .demod_revision = 0xa2,
+ .pll_type = DRXD_PLL_NONE,
+ .clock = 12000,
+ .insert_rs_byte = 1,
+ .IF = 42800000,
.disable_i2c_gate_ctrl = 1,
};
@@ -316,6 +317,27 @@ struct drxk_config terratec_h5_drxk = {
.microcode_name = "dvb-usb-terratec-h5-drxk.fw",
};
+struct drxk_config hauppauge_930c_drxk = {
+ .adr = 0x29,
+ .single_master = 1,
+ .no_i2c_bridge = 1,
+ .microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw",
+ .chunk_size = 56,
+};
+
+struct drxk_config maxmedia_ub425_tc_drxk = {
+ .adr = 0x29,
+ .single_master = 1,
+ .no_i2c_bridge = 1,
+};
+
+struct drxk_config pctv_520e_drxk = {
+ .adr = 0x29,
+ .single_master = 1,
+ .microcode_name = "dvb-demod-drxk-pctv.fw",
+ .chunk_size = 58,
+};
+
static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct em28xx_dvb *dvb = fe->sec_priv;
@@ -334,6 +356,73 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
return status;
}
+static void hauppauge_hvr930c_init(struct em28xx *dev)
+{
+ int i;
+
+ struct em28xx_reg_seq hauppauge_hvr930c_init[] = {
+ {EM2874_R80_GPIO, 0xff, 0xff, 0x65},
+ {EM2874_R80_GPIO, 0xfb, 0xff, 0x32},
+ {EM2874_R80_GPIO, 0xff, 0xff, 0xb8},
+ { -1, -1, -1, -1},
+ };
+ struct em28xx_reg_seq hauppauge_hvr930c_end[] = {
+ {EM2874_R80_GPIO, 0xef, 0xff, 0x01},
+ {EM2874_R80_GPIO, 0xaf, 0xff, 0x65},
+ {EM2874_R80_GPIO, 0xef, 0xff, 0x76},
+ {EM2874_R80_GPIO, 0xef, 0xff, 0x01},
+ {EM2874_R80_GPIO, 0xcf, 0xff, 0x0b},
+ {EM2874_R80_GPIO, 0xef, 0xff, 0x40},
+
+ {EM2874_R80_GPIO, 0xcf, 0xff, 0x65},
+ {EM2874_R80_GPIO, 0xef, 0xff, 0x65},
+ {EM2874_R80_GPIO, 0xcf, 0xff, 0x0b},
+ {EM2874_R80_GPIO, 0xef, 0xff, 0x65},
+
+ { -1, -1, -1, -1},
+ };
+
+ struct {
+ unsigned char r[4];
+ int len;
+ } regs[] = {
+ {{ 0x06, 0x02, 0x00, 0x31 }, 4},
+ {{ 0x01, 0x02 }, 2},
+ {{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+ {{ 0x01, 0x00 }, 2},
+ {{ 0x01, 0x00, 0xff, 0xaf }, 4},
+ {{ 0x01, 0x00, 0x03, 0xa0 }, 4},
+ {{ 0x01, 0x00 }, 2},
+ {{ 0x01, 0x00, 0x73, 0xaf }, 4},
+ {{ 0x04, 0x00 }, 2},
+ {{ 0x00, 0x04 }, 2},
+ {{ 0x00, 0x04, 0x00, 0x0a }, 4},
+ {{ 0x04, 0x14 }, 2},
+ {{ 0x04, 0x14, 0x00, 0x00 }, 4},
+ };
+
+ em28xx_gpio_set(dev, hauppauge_hvr930c_init);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+ msleep(10);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
+ msleep(10);
+
+ dev->i2c_client.addr = 0x82 >> 1;
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++)
+ i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ em28xx_gpio_set(dev, hauppauge_hvr930c_end);
+
+ msleep(100);
+
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
+ msleep(30);
+
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
+ msleep(10);
+
+}
+
static void terratec_h5_init(struct em28xx *dev)
{
int i;
@@ -382,6 +471,33 @@ static void terratec_h5_init(struct em28xx *dev)
em28xx_gpio_set(dev, terratec_h5_end);
};
+static void pctv_520e_init(struct em28xx *dev)
+{
+ /*
+ * Init TDA8295(?) analog demodulator. Looks like I2C traffic to
+ * digital demodulator and tuner are routed via TDA8295.
+ */
+ int i;
+ struct {
+ unsigned char r[4];
+ int len;
+ } regs[] = {
+ {{ 0x06, 0x02, 0x00, 0x31 }, 4},
+ {{ 0x01, 0x02 }, 2},
+ {{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+ {{ 0x01, 0x00 }, 2},
+ {{ 0x01, 0x00, 0xff, 0xaf }, 4},
+ {{ 0x01, 0x00, 0x03, 0xa0 }, 4},
+ {{ 0x01, 0x00 }, 2},
+ {{ 0x01, 0x00, 0x73, 0xaf }, 4},
+ };
+
+ dev->i2c_client.addr = 0x82 >> 1; /* 0x41 */
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++)
+ i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+};
+
static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
{
/* Values extracted from a USB trace of the Terratec Windows driver */
@@ -425,13 +541,6 @@ static struct tda10023_config em28xx_tda10023_config = {
static struct cxd2820r_config em28xx_cxd2820r_config = {
.i2c_address = (0xd8 >> 1),
.ts_mode = CXD2820R_TS_SERIAL,
- .if_dvbt_6 = 3300,
- .if_dvbt_7 = 3500,
- .if_dvbt_8 = 4000,
- .if_dvbt2_6 = 3300,
- .if_dvbt2_7 = 3500,
- .if_dvbt2_8 = 4000,
- .if_dvbc = 5000,
/* enable LNA for DVB-T2 and DVB-C */
.gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
@@ -456,6 +565,17 @@ static const struct a8293_config em28xx_a8293_config = {
.i2c_addr = 0x08, /* (0x10 >> 1) */
};
+static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = {
+ .demod_address = (0x1e >> 1),
+ .disable_i2c_gate_ctrl = 1,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+};
+static struct qt1010_config em28xx_qt1010_config = {
+ .i2c_address = 0x62
+
+};
+
/* ------------------------------------------------------------------ */
static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
@@ -708,6 +828,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
goto out_free;
}
break;
+ case EM2870_BOARD_KWORLD_355U:
+ dvb->fe[0] = dvb_attach(zl10353_attach,
+ &em28xx_zl10353_no_i2c_gate_dev,
+ &dev->i2c_adap);
+ if (dvb->fe[0] != NULL)
+ dvb_attach(qt1010_attach, dvb->fe[0],
+ &dev->i2c_adap, &em28xx_qt1010_config);
+ break;
case EM2883_BOARD_KWORLD_HYBRID_330U:
case EM2882_BOARD_EVGA_INDTUBE:
dvb->fe[0] = dvb_attach(s5h1409_attach,
@@ -761,50 +889,71 @@ static int em28xx_dvb_init(struct em28xx *dev)
&dev->i2c_adap, &kworld_a340_config);
break;
case EM28174_BOARD_PCTV_290E:
- /* MFE
- * FE 0 = DVB-T/T2 + FE 1 = DVB-C, both sharing same tuner. */
- /* FE 0 */
dvb->fe[0] = dvb_attach(cxd2820r_attach,
- &em28xx_cxd2820r_config, &dev->i2c_adap, NULL);
+ &em28xx_cxd2820r_config,
+ &dev->i2c_adap);
if (dvb->fe[0]) {
/* FE 0 attach tuner */
- if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) {
+ if (!dvb_attach(tda18271_attach,
+ dvb->fe[0],
+ 0x60,
+ &dev->i2c_adap,
+ &em28xx_cxd2820r_tda18271_config)) {
+
dvb_frontend_detach(dvb->fe[0]);
result = -EINVAL;
goto out_free;
}
- /* FE 1. This dvb_attach() cannot fail. */
- dvb->fe[1] = dvb_attach(cxd2820r_attach, NULL, NULL,
- dvb->fe[0]);
- dvb->fe[1]->id = 1;
- /* FE 1 attach tuner */
- if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60,
- &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) {
- dvb_frontend_detach(dvb->fe[1]);
- /* leave FE 0 still active */
- }
+ }
+ break;
+ case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
+ {
+ struct xc5000_config cfg;
+ hauppauge_hvr930c_init(dev);
+
+ dvb->fe[0] = dvb_attach(drxk_attach,
+ &hauppauge_930c_drxk, &dev->i2c_adap);
+ if (!dvb->fe[0]) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ /* FIXME: do we need a pll semaphore? */
+ dvb->fe[0]->sec_priv = dvb;
+ sema_init(&dvb->pll_mutex, 1);
+ dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
+ dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+ /* Attach xc5000 */
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.i2c_address = 0x61;
+ cfg.if_khz = 4000;
- mfe_shared = 1;
+ if (dvb->fe[0]->ops.i2c_gate_ctrl)
+ dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
+ if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap,
+ &cfg)) {
+ result = -EINVAL;
+ goto out_free;
}
+ if (dvb->fe[0]->ops.i2c_gate_ctrl)
+ dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
+
break;
+ }
case EM2884_BOARD_TERRATEC_H5:
+ case EM2884_BOARD_CINERGY_HTC_STICK:
terratec_h5_init(dev);
- dvb->dont_attach_fe1 = 1;
-
- dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap, &dvb->fe[1]);
+ dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
}
-
/* FIXME: do we need a pll semaphore? */
dvb->fe[0]->sec_priv = dvb;
sema_init(&dvb->pll_mutex, 1);
dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
- dvb->fe[1]->id = 1;
/* Attach tda18271 to DVB-C frontend */
if (dvb->fe[0]->ops.i2c_gate_ctrl)
@@ -816,12 +965,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
- /* Hack - needed by drxk/tda18271c2dd */
- dvb->fe[1]->tuner_priv = dvb->fe[0]->tuner_priv;
- memcpy(&dvb->fe[1]->ops.tuner_ops,
- &dvb->fe[0]->ops.tuner_ops,
- sizeof(dvb->fe[0]->ops.tuner_ops));
-
break;
case EM28174_BOARD_PCTV_460E:
/* attach demod */
@@ -833,6 +976,48 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap,
&em28xx_a8293_config);
break;
+ case EM2874_BOARD_MAXMEDIA_UB425_TC:
+ /* attach demodulator */
+ dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
+ &dev->i2c_adap);
+
+ if (dvb->fe[0]) {
+ /* disable I2C-gate */
+ dvb->fe[0]->ops.i2c_gate_ctrl = NULL;
+
+ /* attach tuner */
+ if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
+ &dev->i2c_adap, 0x60)) {
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -EINVAL;
+ goto out_free;
+ }
+ }
+
+ /* TODO: we need drx-3913k firmware in order to support DVB-T */
+ em28xx_info("MaxMedia UB425-TC: only DVB-C supported by that " \
+ "driver version\n");
+
+ break;
+ case EM2884_BOARD_PCTV_510E:
+ case EM2884_BOARD_PCTV_520E:
+ pctv_520e_init(dev);
+
+ /* attach demodulator */
+ dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk,
+ &dev->i2c_adap);
+
+ if (dvb->fe[0]) {
+ /* attach tuner */
+ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ &dev->i2c_adap,
+ &em28xx_cxd2820r_tda18271_config)) {
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -EINVAL;
+ goto out_free;
+ }
+ }
+ break;
default:
em28xx_errdev("/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n");
@@ -845,6 +1030,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
}
/* define general-purpose callback pointer */
dvb->fe[0]->callback = em28xx_tuner_callback;
+ if (dvb->fe[1])
+ dvb->fe[1]->callback = em28xx_tuner_callback;
/* register everything */
result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 36f5a9bc8b76..a88e169dba23 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -41,14 +41,6 @@ static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-
-#define dprintk1(lvl, fmt, args...) \
-do { \
- if (i2c_debug >= lvl) { \
- printk(fmt, ##args); \
- } \
-} while (0)
-
#define dprintk2(lvl, fmt, args...) \
do { \
if (i2c_debug >= lvl) { \
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 679da4804281..2630b265b0e8 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -306,7 +306,8 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
poll_result.rc_data[0],
poll_result.toggle_bit);
- if (ir->dev->chip_id == CHIP_ID_EM2874)
+ if (ir->dev->chip_id == CHIP_ID_EM2874 ||
+ ir->dev->chip_id == CHIP_ID_EM2884)
/* The em2874 clears the readcount field every time the
register is read. The em2860/2880 datasheet says that it
is supposed to clear the readcount, but it doesn't. So with
@@ -371,13 +372,15 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
case CHIP_ID_EM2883:
ir->get_key = default_polling_getkey;
break;
+ case CHIP_ID_EM2884:
case CHIP_ID_EM2874:
case CHIP_ID_EM28174:
ir->get_key = em2874_polling_getkey;
em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
break;
default:
- printk("Unrecognized em28xx chip id: IR not supported\n");
+ printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n",
+ dev->chip_id);
rc = -EINVAL;
}
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
index 66f792361b97..2f6268505726 100644
--- a/drivers/media/video/em28xx/em28xx-reg.h
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -12,6 +12,11 @@
#define EM_GPO_2 (1 << 2)
#define EM_GPO_3 (1 << 3)
+/* em28xx endpoints */
+#define EM28XX_EP_ANALOG 0x82
+#define EM28XX_EP_AUDIO 0x83
+#define EM28XX_EP_DIGITAL 0x84
+
/* em2800 registers */
#define EM2800_R08_AUDIOSRC 0x08
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 9b4557a2f6d0..324b695c0724 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -760,17 +760,19 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
goto fail;
}
- if (!dev->isoc_ctl.num_bufs)
+ if (!dev->isoc_ctl.analog_bufs.num_bufs)
urb_init = 1;
if (urb_init) {
if (em28xx_vbi_supported(dev) == 1)
- rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+ rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
+ EM28XX_NUM_PACKETS,
EM28XX_NUM_BUFS,
dev->max_pkt_size,
em28xx_isoc_copy_vbi);
else
- rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+ rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
+ EM28XX_NUM_PACKETS,
EM28XX_NUM_BUFS,
dev->max_pkt_size,
em28xx_isoc_copy);
@@ -1070,6 +1072,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
/* the em2800 can only scale down to 50% */
height = height > (3 * maxh / 4) ? maxh : maxh / 2;
width = width > (3 * maxw / 4) ? maxw : maxw / 2;
+ /* MaxPacketSize for em2800 is too small to capture at full resolution
+ * use half of maxw as the scaler can only scale to 50% */
+ if (width == maxw && height == maxh)
+ width /= 2;
} else {
/* width must even because of the YUYV format
height must be even because of interlacing */
@@ -2263,7 +2269,7 @@ static int em28xx_v4l2_close(struct file *filp)
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
/* do this before setting alternate! */
- em28xx_uninit_isoc(dev);
+ em28xx_uninit_isoc(dev, EM28XX_ANALOG_MODE);
em28xx_set_mode(dev, EM28XX_SUSPEND);
/* set alternate 0 */
@@ -2503,6 +2509,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
{
u8 val;
int ret;
+ unsigned int maxw;
printk(KERN_INFO "%s: v4l2 driver version %s\n",
dev->name, EM28XX_VERSION);
@@ -2515,8 +2522,15 @@ int em28xx_register_analog_devices(struct em28xx *dev)
/* Analog specific initialization */
dev->format = &format[0];
+
+ maxw = norm_maxw(dev);
+ /* MaxPacketSize for em2800 is too small to capture at full resolution
+ * use half of maxw as the scaler can only scale to 50% */
+ if (dev->board.is_em2800)
+ maxw /= 2;
+
em28xx_set_video_format(dev, format[0].fourcc,
- norm_maxw(dev), norm_maxh(dev));
+ maxw, norm_maxh(dev));
video_mux(dev, dev->ctl_input);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 2a2cb7ed0014..2868b19f8b54 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -38,6 +38,7 @@
#include <media/videobuf-dvb.h>
#endif
#include "tuner-xc2028.h"
+#include "xc5000.h"
#include "em28xx-reg.h"
/* Boards supported by driver */
@@ -121,6 +122,12 @@
#define EM28174_BOARD_PCTV_290E 78
#define EM2884_BOARD_TERRATEC_H5 79
#define EM28174_BOARD_PCTV_460E 80
+#define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81
+#define EM2884_BOARD_CINERGY_HTC_STICK 82
+#define EM2860_BOARD_HT_VIDBOX_NW03 83
+#define EM2874_BOARD_MAXMEDIA_UB425_TC 84
+#define EM2884_BOARD_PCTV_510E 85
+#define EM2884_BOARD_PCTV_520E 86
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -147,12 +154,14 @@
/* number of buffers for isoc transfers */
#define EM28XX_NUM_BUFS 5
+#define EM28XX_DVB_NUM_BUFS 5
/* number of packets for each buffer
windows requests only 64 packets .. so we better do the same
this is what I found out for all alternate numbers there!
*/
#define EM28XX_NUM_PACKETS 64
+#define EM28XX_DVB_MAX_PACKETS 64
#define EM28XX_INTERLACED_DEFAULT 1
@@ -193,10 +202,13 @@ enum em28xx_mode {
struct em28xx;
-struct em28xx_usb_isoc_ctl {
+struct em28xx_usb_isoc_bufs {
/* max packet size of isoc transaction */
int max_pkt_size;
+ /* number of packets in each buffer */
+ int num_packets;
+
/* number of allocated urbs */
int num_bufs;
@@ -205,6 +217,14 @@ struct em28xx_usb_isoc_ctl {
/* transfer buffers for isoc transfer */
char **transfer_buffer;
+};
+
+struct em28xx_usb_isoc_ctl {
+ /* isoc transfer buffers for analog mode */
+ struct em28xx_usb_isoc_bufs analog_bufs;
+
+ /* isoc transfer buffers for digital mode */
+ struct em28xx_usb_isoc_bufs digital_bufs;
/* Last buffer command and region */
u8 cmd;
@@ -594,9 +614,8 @@ struct em28xx {
int max_pkt_size; /* max packet size of isoc transaction */
int num_alt; /* Number of alternative settings */
unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
- struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */
- char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc
- transfer */
+ int dvb_alt; /* alternate for DVB */
+ unsigned int dvb_max_pkt_size; /* wMaxPacketSize for DVB */
char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
/* helper funcs that call usb_control_msg */
@@ -670,10 +689,12 @@ int em28xx_vbi_supported(struct em28xx *dev);
int em28xx_set_outfmt(struct em28xx *dev);
int em28xx_resolution_set(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
-int em28xx_init_isoc(struct em28xx *dev, int max_packets,
- int num_bufs, int max_pkt_size,
+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
+ int max_packets, int num_bufs, int max_pkt_size);
+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
+ int max_packets, int num_bufs, int max_pkt_size,
int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
-void em28xx_uninit_isoc(struct em28xx *dev);
+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode);
int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
@@ -825,7 +846,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev)
if (dev->board.is_webcam)
return dev->sensor_xres;
- if (dev->board.max_range_640_480 || dev->board.is_em2800)
+ if (dev->board.max_range_640_480)
return 640;
return 720;
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 40f214ab924f..5539f09440ac 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -76,8 +76,8 @@ MODULE_PARM_DESC(video_nr,
"\none and for every other camera."
"\n");
-static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
- ET61X251_FORCE_MUNMAP};
+static bool force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
+ ET61X251_FORCE_MUNMAP};
module_param_array(force_munmap, bool, NULL, 0444);
MODULE_PARM_DESC(force_munmap,
"\n<0|1[,...]> Force the application to unmap previously"
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
index 27cb197d0bd6..27e3e0c0b219 100644
--- a/drivers/media/video/fsl-viu.c
+++ b/drivers/media/video/fsl-viu.c
@@ -1661,18 +1661,7 @@ static struct platform_driver viu_of_platform_driver = {
},
};
-static int __init viu_init(void)
-{
- return platform_driver_register(&viu_of_platform_driver);
-}
-
-static void __exit viu_exit(void)
-{
- platform_driver_unregister(&viu_of_platform_driver);
-}
-
-module_init(viu_init);
-module_exit(viu_exit);
+module_platform_driver(viu_of_platform_driver);
MODULE_DESCRIPTION("Freescale Video-In(VIU)");
MODULE_AUTHOR("Hongjun Chen");
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index 103af3fe5aa0..dfe268bfa4f8 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -77,6 +77,16 @@ config USB_GSPCA_JEILINJ
To compile this driver as a module, choose M here: the
module will be called gspca_jeilinj.
+config USB_GSPCA_JL2005BCD
+ tristate "JL2005B/C/D USB V4L2 driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based the
+ JL2005B, JL2005C, or JL2005D chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_jl2005bcd.
+
config USB_GSPCA_KINECT
tristate "Kinect sensor device USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index f345f494d0f3..79ebe46e1ad7 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o
obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o
+obj-$(CONFIG_USB_GSPCA_JL2005BCD) += gspca_jl2005bcd.o
obj-$(CONFIG_USB_GSPCA_KINECT) += gspca_kinect.o
obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o
obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o
@@ -49,6 +50,7 @@ gspca_cpia1-objs := cpia1.o
gspca_etoms-objs := etoms.o
gspca_finepix-objs := finepix.o
gspca_jeilinj-objs := jeilinj.o
+gspca_jl2005bcd-objs := jl2005bcd.o
gspca_kinect-objs := kinect.o
gspca_konica-objs := konica.o
gspca_mars-objs := mars.o
diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c
index 636627b57dc9..9769f17915c0 100644
--- a/drivers/media/video/gspca/benq.c
+++ b/drivers/media/video/gspca/benq.c
@@ -76,7 +76,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
gspca_dev->cam.cam_mode = vga_mode;
gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
gspca_dev->cam.no_urb_create = 1;
- gspca_dev->cam.reverse_alts = 1;
return 0;
}
@@ -135,13 +134,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(struct gspca_dev *gspca_dev)
{
+ struct usb_interface *intf;
+
reg_w(gspca_dev, 0x003c, 0x0003);
reg_w(gspca_dev, 0x003c, 0x0004);
reg_w(gspca_dev, 0x003c, 0x0005);
reg_w(gspca_dev, 0x003c, 0x0006);
reg_w(gspca_dev, 0x003c, 0x0007);
+
+ intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
usb_set_interface(gspca_dev->dev, gspca_dev->iface,
- gspca_dev->nbalt - 1);
+ intf->num_altsetting - 1);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
diff --git a/drivers/media/video/gspca/gl860/Makefile b/drivers/media/video/gspca/gl860/Makefile
index f511eccdfd9c..773ea3426561 100644
--- a/drivers/media/video/gspca/gl860/Makefile
+++ b/drivers/media/video/gspca/gl860/Makefile
@@ -6,5 +6,5 @@ gspca_gl860-objs := gl860.o \
gl860-ov9655.o \
gl860-mi2020.o
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index a8f54c20e585..c84e26006fc3 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -337,7 +337,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
return -1;
cam = &gspca_dev->cam;
- gspca_dev->nbalt = 4;
switch (sd->sensor) {
case ID_MI1320:
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 2ca10dfec91f..ca5a2b139d0b 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -633,23 +633,32 @@ static u32 which_bandwidth(struct gspca_dev *gspca_dev)
u32 bandwidth;
int i;
+ /* get the (max) image size */
i = gspca_dev->curr_mode;
bandwidth = gspca_dev->cam.cam_mode[i].sizeimage;
- /* if the image is compressed, estimate the mean image size */
- if (bandwidth < gspca_dev->cam.cam_mode[i].width *
+ /* if the image is compressed, estimate its mean size */
+ if (!gspca_dev->cam.needs_full_bandwidth &&
+ bandwidth < gspca_dev->cam.cam_mode[i].width *
gspca_dev->cam.cam_mode[i].height)
- bandwidth /= 3;
+ bandwidth = bandwidth * 3 / 8; /* 0.375 */
/* estimate the frame rate */
if (gspca_dev->sd_desc->get_streamparm) {
struct v4l2_streamparm parm;
- parm.parm.capture.timeperframe.denominator = 15;
gspca_dev->sd_desc->get_streamparm(gspca_dev, &parm);
bandwidth *= parm.parm.capture.timeperframe.denominator;
+ bandwidth /= parm.parm.capture.timeperframe.numerator;
} else {
- bandwidth *= 15; /* 15 fps */
+
+ /* don't hope more than 15 fps with USB 1.1 and
+ * image resolution >= 640x480 */
+ if (gspca_dev->width >= 640
+ && gspca_dev->dev->speed == USB_SPEED_FULL)
+ bandwidth *= 15; /* 15 fps */
+ else
+ bandwidth *= 30; /* 30 fps */
}
PDEBUG(D_STREAM, "min bandwidth: %d", bandwidth);
@@ -667,9 +676,8 @@ struct ep_tb_s {
* build the table of the endpoints
* and compute the minimum bandwidth for the image transfer
*/
-static int build_ep_tb(struct gspca_dev *gspca_dev,
+static int build_isoc_ep_tb(struct gspca_dev *gspca_dev,
struct usb_interface *intf,
- int xfer,
struct ep_tb_s *ep_tb)
{
struct usb_host_endpoint *ep;
@@ -687,17 +695,21 @@ static int build_ep_tb(struct gspca_dev *gspca_dev,
ep_tb->bandwidth = 2000 * 2000 * 120;
found = 0;
for (j = 0; j < nbalt; j++) {
- ep = alt_xfer(&intf->altsetting[j], xfer);
+ ep = alt_xfer(&intf->altsetting[j],
+ USB_ENDPOINT_XFER_ISOC);
if (ep == NULL)
continue;
+ if (ep->desc.bInterval == 0) {
+ pr_err("alt %d iso endp with 0 interval\n", j);
+ continue;
+ }
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
- if (!gspca_dev->cam.bulk) /* isoc */
- psize = (psize & 0x07ff) *
- (1 + ((psize >> 11) & 3));
- bandwidth = psize * ep->desc.bInterval * 1000;
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ bandwidth = psize * 1000;
if (gspca_dev->dev->speed == USB_SPEED_HIGH
|| gspca_dev->dev->speed == USB_SPEED_SUPER)
bandwidth *= 8;
+ bandwidth /= 1 << (ep->desc.bInterval - 1);
if (bandwidth <= last_bw)
continue;
if (bandwidth < ep_tb->bandwidth) {
@@ -715,6 +727,23 @@ static int build_ep_tb(struct gspca_dev *gspca_dev,
ep_tb++;
}
+ /*
+ * If the camera:
+ * has a usb audio class interface (a built in usb mic); and
+ * is a usb 1 full speed device; and
+ * uses the max full speed iso bandwidth; and
+ * and has more than 1 alt setting
+ * then skip the highest alt setting to spare bandwidth for the mic
+ */
+ if (gspca_dev->audio &&
+ gspca_dev->dev->speed == USB_SPEED_FULL &&
+ last_bw >= 1000000 &&
+ i > 1) {
+ PDEBUG(D_STREAM, "dev has usb audio, skipping highest alt");
+ i--;
+ ep_tb--;
+ }
+
/* get the requested bandwidth and start at the highest atlsetting */
bandwidth = which_bandwidth(gspca_dev);
ep_tb--;
@@ -790,10 +819,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
ep->desc.bEndpointAddress);
urb->transfer_flags = URB_ISO_ASAP
| URB_NO_TRANSFER_DMA_MAP;
- if (gspca_dev->dev->speed == USB_SPEED_LOW)
- urb->interval = ep->desc.bInterval;
- else
- urb->interval = 1 << (ep->desc.bInterval - 1);
+ urb->interval = 1 << (ep->desc.bInterval - 1);
urb->complete = isoc_irq;
urb->number_of_packets = npkt;
for (i = 0; i < npkt; i++) {
@@ -848,7 +874,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
: USB_ENDPOINT_XFER_ISOC;
- /* if the subdriver forced an altsetting, get the endpoint */
+ /* if bulk or the subdriver forced an altsetting, get the endpoint */
if (gspca_dev->alt != 0) {
gspca_dev->alt--; /* (previous version compatibility) */
ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer);
@@ -863,7 +889,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* else, compute the minimum bandwidth
* and build the endpoint table */
- alt_idx = build_ep_tb(gspca_dev, intf, xfer, ep_tb);
+ alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb);
if (alt_idx <= 0) {
pr_err("no transfer endpoint found\n");
ret = -EIO;
@@ -880,7 +906,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
for (;;) {
if (alt != gspca_dev->alt) {
alt = gspca_dev->alt;
- if (gspca_dev->nbalt > 1) {
+ if (intf->num_altsetting > 1) {
ret = usb_set_interface(gspca_dev->dev,
gspca_dev->iface,
alt);
@@ -2300,15 +2326,14 @@ int gspca_dev_probe2(struct usb_interface *intf,
}
gspca_dev->dev = dev;
gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber;
- gspca_dev->nbalt = intf->num_altsetting;
/* check if any audio device */
- if (dev->config->desc.bNumInterfaces != 1) {
+ if (dev->actconfig->desc.bNumInterfaces != 1) {
int i;
struct usb_interface *intf2;
- for (i = 0; i < dev->config->desc.bNumInterfaces; i++) {
- intf2 = dev->config->interface[i];
+ for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+ intf2 = dev->actconfig->interface[i];
if (intf2 != NULL
&& intf2->altsetting != NULL
&& intf2->altsetting->desc.bInterfaceClass ==
@@ -2389,7 +2414,7 @@ int gspca_dev_probe(struct usb_interface *intf,
}
/* the USB video interface must be the first one */
- if (dev->config->desc.bNumInterfaces != 1
+ if (dev->actconfig->desc.bNumInterfaces != 1
&& intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index e444f16e1497..589009f4496f 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -69,7 +69,9 @@ struct cam {
u8 bulk; /* image transfer by 0:isoc / 1:bulk */
u8 npkt; /* number of packets in an ISOC message
* 0 is the default value: 32 packets */
- u8 reverse_alts; /* Alt settings are in high to low order */
+ u8 needs_full_bandwidth;/* Set this flag to notify the bandwidth calc.
+ * code that the cam fills all image buffers to
+ * the max, even when using compression. */
};
struct gspca_dev;
@@ -208,7 +210,6 @@ struct gspca_dev {
char memory; /* memory type (V4L2_MEMORY_xxx) */
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
- __u8 nbalt; /* number of USB alternate settings */
u8 audio; /* presence of audio device */
};
diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/video/gspca/jl2005bcd.c
new file mode 100644
index 000000000000..53f58ef367cf
--- /dev/null
+++ b/drivers/media/video/gspca/jl2005bcd.c
@@ -0,0 +1,554 @@
+/*
+ * Jeilin JL2005B/C/D library
+ *
+ * Copyright (C) 2011 Theodore Kilgore <kilgota@auburn.edu>
+ *
+ * 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
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "jl2005bcd"
+
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include "gspca.h"
+
+
+MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("JL2005B/C/D USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define JL2005C_CMD_TIMEOUT 500
+#define JL2005C_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define JL2005C_MAX_TRANSFER 0x200
+#define FRAME_HEADER_LEN 16
+
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ unsigned char firmware_id[6];
+ const struct v4l2_pix_format *cap_mode;
+ /* Driver stuff */
+ struct work_struct work_struct;
+ struct workqueue_struct *work_thread;
+ u8 frame_brightness;
+ int block_size; /* block size of camera */
+ int vga; /* 1 if vga cam, 0 if cif cam */
+};
+
+
+/* Camera has two resolution settings. What they are depends on model. */
+static const struct v4l2_pix_format cif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ {352, 288, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ {640, 480, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/*
+ * cam uses endpoint 0x03 to send commands, 0x84 for read commands,
+ * and 0x82 for bulk data transfer.
+ */
+
+/* All commands are two bytes only */
+static int jl2005c_write2(struct gspca_dev *gspca_dev, unsigned char *command)
+{
+ int retval;
+
+ memcpy(gspca_dev->usb_buf, command, 2);
+ retval = usb_bulk_msg(gspca_dev->dev,
+ usb_sndbulkpipe(gspca_dev->dev, 3),
+ gspca_dev->usb_buf, 2, NULL, 500);
+ if (retval < 0)
+ pr_err("command write [%02x] error %d\n",
+ gspca_dev->usb_buf[0], retval);
+ return retval;
+}
+
+/* Response to a command is one byte in usb_buf[0], only if requested. */
+static int jl2005c_read1(struct gspca_dev *gspca_dev)
+{
+ int retval;
+
+ retval = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x84),
+ gspca_dev->usb_buf, 1, NULL, 500);
+ if (retval < 0)
+ pr_err("read command [0x%02x] error %d\n",
+ gspca_dev->usb_buf[0], retval);
+ return retval;
+}
+
+/* Response appears in gspca_dev->usb_buf[0] */
+static int jl2005c_read_reg(struct gspca_dev *gspca_dev, unsigned char reg)
+{
+ int retval;
+
+ static u8 instruction[2] = {0x95, 0x00};
+ /* put register to read in byte 1 */
+ instruction[1] = reg;
+ /* Send the read request */
+ retval = jl2005c_write2(gspca_dev, instruction);
+ if (retval < 0)
+ return retval;
+ retval = jl2005c_read1(gspca_dev);
+
+ return retval;
+}
+
+static int jl2005c_start_new_frame(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval;
+ int frame_brightness = 0;
+
+ static u8 instruction[2] = {0x7f, 0x01};
+
+ retval = jl2005c_write2(gspca_dev, instruction);
+ if (retval < 0)
+ return retval;
+
+ i = 0;
+ while (i < 20 && !frame_brightness) {
+ /* If we tried 20 times, give up. */
+ retval = jl2005c_read_reg(gspca_dev, 0x7e);
+ if (retval < 0)
+ return retval;
+ frame_brightness = gspca_dev->usb_buf[0];
+ retval = jl2005c_read_reg(gspca_dev, 0x7d);
+ if (retval < 0)
+ return retval;
+ i++;
+ }
+ PDEBUG(D_FRAM, "frame_brightness is 0x%02x", gspca_dev->usb_buf[0]);
+ return retval;
+}
+
+static int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg,
+ unsigned char value)
+{
+ int retval;
+ u8 instruction[2];
+
+ instruction[0] = reg;
+ instruction[1] = value;
+
+ retval = jl2005c_write2(gspca_dev, instruction);
+ if (retval < 0)
+ return retval;
+
+ return retval;
+}
+
+static int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *)gspca_dev;
+ int i = 0;
+ int retval = -1;
+ unsigned char regs_to_read[] = {0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f};
+
+ PDEBUG(D_PROBE, "Running jl2005c_get_firmware_id");
+ /* Read the first ID byte once for warmup */
+ retval = jl2005c_read_reg(gspca_dev, regs_to_read[0]);
+ PDEBUG(D_PROBE, "response is %02x", gspca_dev->usb_buf[0]);
+ if (retval < 0)
+ return retval;
+ /* Now actually get the ID string */
+ for (i = 0; i < 6; i++) {
+ retval = jl2005c_read_reg(gspca_dev, regs_to_read[i]);
+ if (retval < 0)
+ return retval;
+ sd->firmware_id[i] = gspca_dev->usb_buf[0];
+ }
+ PDEBUG(D_PROBE, "firmware ID is %02x%02x%02x%02x%02x%02x",
+ sd->firmware_id[0],
+ sd->firmware_id[1],
+ sd->firmware_id[2],
+ sd->firmware_id[3],
+ sd->firmware_id[4],
+ sd->firmware_id[5]);
+ return 0;
+}
+
+static int jl2005c_stream_start_vga_lg
+ (struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval = -1;
+ static u8 instruction[][2] = {
+ {0x05, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x18},
+ {0x02, 0x00},
+ {0x01, 0x00},
+ {0x04, 0x52},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+ msleep(60);
+ retval = jl2005c_write2(gspca_dev, instruction[i]);
+ if (retval < 0)
+ return retval;
+ }
+ msleep(60);
+ return retval;
+}
+
+static int jl2005c_stream_start_vga_small(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval = -1;
+ static u8 instruction[][2] = {
+ {0x06, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x1a},
+ {0x02, 0x00},
+ {0x01, 0x00},
+ {0x04, 0x52},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+ msleep(60);
+ retval = jl2005c_write2(gspca_dev, instruction[i]);
+ if (retval < 0)
+ return retval;
+ }
+ msleep(60);
+ return retval;
+}
+
+static int jl2005c_stream_start_cif_lg(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval = -1;
+ static u8 instruction[][2] = {
+ {0x05, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x30},
+ {0x02, 0x00},
+ {0x01, 0x00},
+ {0x04, 0x42},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+ msleep(60);
+ retval = jl2005c_write2(gspca_dev, instruction[i]);
+ if (retval < 0)
+ return retval;
+ }
+ msleep(60);
+ return retval;
+}
+
+static int jl2005c_stream_start_cif_small(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval = -1;
+ static u8 instruction[][2] = {
+ {0x06, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x32},
+ {0x02, 0x00},
+ {0x01, 0x00},
+ {0x04, 0x42},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+ msleep(60);
+ retval = jl2005c_write2(gspca_dev, instruction[i]);
+ if (retval < 0)
+ return retval;
+ }
+ msleep(60);
+ return retval;
+}
+
+
+static int jl2005c_stop(struct gspca_dev *gspca_dev)
+{
+ int retval;
+
+ retval = jl2005c_write_reg(gspca_dev, 0x07, 0x00);
+ return retval;
+}
+
+/* This function is called as a workqueue function and runs whenever the camera
+ * is streaming data. Because it is a workqueue function it is allowed to sleep
+ * so we can use synchronous USB calls. To avoid possible collisions with other
+ * threads attempting to use the camera's USB interface the gspca usb_lock is
+ * used when performing the one USB control operation inside the workqueue,
+ * which tells the camera to close the stream. In practice the only thing
+ * which needs to be protected against is the usb_set_interface call that
+ * gspca makes during stream_off. Otherwise the camera doesn't provide any
+ * controls that the user could try to change.
+ */
+static void jl2005c_dostream(struct work_struct *work)
+{
+ struct sd *dev = container_of(work, struct sd, work_struct);
+ struct gspca_dev *gspca_dev = &dev->gspca_dev;
+ int bytes_left = 0; /* bytes remaining in current frame. */
+ int data_len; /* size to use for the next read. */
+ int header_read = 0;
+ unsigned char header_sig[2] = {0x4a, 0x4c};
+ int act_len;
+ int packet_type;
+ int ret;
+ u8 *buffer;
+
+ buffer = kmalloc(JL2005C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
+ pr_err("Couldn't allocate USB buffer\n");
+ goto quit_stream;
+ }
+
+ while (gspca_dev->present && gspca_dev->streaming) {
+ /* Check if this is a new frame. If so, start the frame first */
+ if (!header_read) {
+ mutex_lock(&gspca_dev->usb_lock);
+ ret = jl2005c_start_new_frame(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ if (ret < 0)
+ goto quit_stream;
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+ buffer, JL2005C_MAX_TRANSFER, &act_len,
+ JL2005C_DATA_TIMEOUT);
+ PDEBUG(D_PACK,
+ "Got %d bytes out of %d for header",
+ act_len, JL2005C_MAX_TRANSFER);
+ if (ret < 0 || act_len < JL2005C_MAX_TRANSFER)
+ goto quit_stream;
+ /* Check whether we actually got the first blodk */
+ if (memcmp(header_sig, buffer, 2) != 0) {
+ pr_err("First block is not the first block\n");
+ goto quit_stream;
+ }
+ /* total size to fetch is byte 7, times blocksize
+ * of which we already got act_len */
+ bytes_left = buffer[0x07] * dev->block_size - act_len;
+ PDEBUG(D_PACK, "bytes_left = 0x%x", bytes_left);
+ /* We keep the header. It has other information, too.*/
+ packet_type = FIRST_PACKET;
+ gspca_frame_add(gspca_dev, packet_type,
+ buffer, act_len);
+ header_read = 1;
+ }
+ while (bytes_left > 0 && gspca_dev->present) {
+ data_len = bytes_left > JL2005C_MAX_TRANSFER ?
+ JL2005C_MAX_TRANSFER : bytes_left;
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+ buffer, data_len, &act_len,
+ JL2005C_DATA_TIMEOUT);
+ if (ret < 0 || act_len < data_len)
+ goto quit_stream;
+ PDEBUG(D_PACK,
+ "Got %d bytes out of %d for frame",
+ data_len, bytes_left);
+ bytes_left -= data_len;
+ if (bytes_left == 0) {
+ packet_type = LAST_PACKET;
+ header_read = 0;
+ } else
+ packet_type = INTER_PACKET;
+ gspca_frame_add(gspca_dev, packet_type,
+ buffer, data_len);
+ }
+ }
+quit_stream:
+ if (gspca_dev->present) {
+ mutex_lock(&gspca_dev->usb_lock);
+ jl2005c_stop(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
+ kfree(buffer);
+}
+
+
+
+
+/* This function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct cam *cam;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ cam = &gspca_dev->cam;
+ /* We don't use the buffer gspca allocates so make it small. */
+ cam->bulk_size = 64;
+ cam->bulk = 1;
+ /* For the rest, the camera needs to be detected */
+ jl2005c_get_firmware_id(gspca_dev);
+ /* Here are some known firmware IDs
+ * First some JL2005B cameras
+ * {0x41, 0x07, 0x04, 0x2c, 0xe8, 0xf2} Sakar KidzCam
+ * {0x45, 0x02, 0x08, 0xb9, 0x00, 0xd2} No-name JL2005B
+ * JL2005C cameras
+ * {0x01, 0x0c, 0x16, 0x10, 0xf8, 0xc8} Argus DC-1512
+ * {0x12, 0x04, 0x03, 0xc0, 0x00, 0xd8} ICarly
+ * {0x86, 0x08, 0x05, 0x02, 0x00, 0xd4} Jazz
+ *
+ * Based upon this scanty evidence, we can detect a CIF camera by
+ * testing byte 0 for 0x4x.
+ */
+ if ((sd->firmware_id[0] & 0xf0) == 0x40) {
+ cam->cam_mode = cif_mode;
+ cam->nmodes = ARRAY_SIZE(cif_mode);
+ sd->block_size = 0x80;
+ } else {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ sd->block_size = 0x200;
+ }
+
+ INIT_WORK(&sd->work_struct, jl2005c_dostream);
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+
+ struct sd *sd = (struct sd *) gspca_dev;
+ sd->cap_mode = gspca_dev->cam.cam_mode;
+
+ switch (gspca_dev->width) {
+ case 640:
+ PDEBUG(D_STREAM, "Start streaming at vga resolution");
+ jl2005c_stream_start_vga_lg(gspca_dev);
+ break;
+ case 320:
+ PDEBUG(D_STREAM, "Start streaming at qvga resolution");
+ jl2005c_stream_start_vga_small(gspca_dev);
+ break;
+ case 352:
+ PDEBUG(D_STREAM, "Start streaming at cif resolution");
+ jl2005c_stream_start_cif_lg(gspca_dev);
+ break;
+ case 176:
+ PDEBUG(D_STREAM, "Start streaming at qcif resolution");
+ jl2005c_stream_start_cif_small(gspca_dev);
+ break;
+ default:
+ pr_err("Unknown resolution specified\n");
+ return -1;
+ }
+
+ /* Start the workqueue function to do the streaming */
+ sd->work_thread = create_singlethread_workqueue(MODULE_NAME);
+ queue_work(sd->work_thread, &sd->work_struct);
+
+ return 0;
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *dev = (struct sd *) gspca_dev;
+
+ /* wait for the work queue to terminate */
+ mutex_unlock(&gspca_dev->usb_lock);
+ /* This waits for sq905c_dostream to finish */
+ destroy_workqueue(dev->work_thread);
+ dev->work_thread = NULL;
+ mutex_lock(&gspca_dev->usb_lock);
+}
+
+
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ /* .ctrls = none have been detected */
+ /* .nctrls = ARRAY_SIZE(sd_ctrls), */
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stop0 = sd_stop0,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0979, 0x0227)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c
index b1da7f4096c8..f0c0d74dfe92 100644
--- a/drivers/media/video/gspca/konica.c
+++ b/drivers/media/video/gspca/konica.c
@@ -247,9 +247,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
gspca_dev->cam.cam_mode = vga_mode;
gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
gspca_dev->cam.no_urb_create = 1;
- /* The highest alt setting has an isoc packetsize of 0, so we
- don't want to use it */
- gspca_dev->nbalt--;
sd->brightness = BRIGHTNESS_DEFAULT;
sd->contrast = CONTRAST_DEFAULT;
diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile
index 7f52961f439c..575b75bacb62 100644
--- a/drivers/media/video/gspca/m5602/Makefile
+++ b/drivers/media/video/gspca/m5602/Makefile
@@ -8,4 +8,4 @@ gspca_m5602-objs := m5602_core.o \
m5602_s5k83a.o \
m5602_s5k4aa.o
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index 9fe3816b2aa0..0c4493675438 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -27,8 +27,8 @@
/* Kernel module parameters */
int force_sensor;
-static int dump_bridge;
-int dump_sensor;
+static bool dump_bridge;
+bool dump_sensor;
static const struct usb_device_id m5602_table[] = {
{USB_DEVICE(0x0402, 0x5602)},
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
index b1f0c492036a..8c672b5c8c6a 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.h
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
@@ -106,7 +106,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int mt9m111_probe(struct sd *sd);
int mt9m111_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h
index 2efd607987ec..2b6a13b508f7 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov7660.h
+++ b/drivers/media/video/gspca/m5602/m5602_ov7660.h
@@ -86,7 +86,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int ov7660_probe(struct sd *sd);
int ov7660_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h
index da9a129b739d..f7aa5bf68983 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.h
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.h
@@ -135,7 +135,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int ov9650_probe(struct sd *sd);
int ov9650_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h
index 338359596398..81a2bcb88fe3 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.h
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.h
@@ -147,7 +147,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int po1030_probe(struct sd *sd);
int po1030_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
index 8cc7a3f6da72..8e0035e731c7 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
@@ -65,7 +65,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int s5k4aa_probe(struct sd *sd);
int s5k4aa_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
index 80a63a236e24..79952247b534 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
@@ -41,7 +41,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int s5k83a_probe(struct sd *sd);
int s5k83a_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index 5c2ea05c46b4..b0231465afae 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -263,7 +263,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->nmodes = ARRAY_SIZE(vga_mode);
cam->ctrls = sd->ctrls;
sd->quality = QUALITY_DEF;
- gspca_dev->nbalt = 9; /* use the altsetting 08 */
return 0;
}
diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c
index d4bec9321771..7167cac7359c 100644
--- a/drivers/media/video/gspca/nw80x.c
+++ b/drivers/media/video/gspca/nw80x.c
@@ -1763,8 +1763,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
if ((unsigned) webcam >= NWEBCAMS)
webcam = 0;
sd->webcam = webcam;
- gspca_dev->cam.reverse_alts = 1;
gspca_dev->cam.ctrls = sd->ctrls;
+ gspca_dev->cam.needs_full_bandwidth = 1;
sd->ag_cnt = -1;
/*
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index 08b8ce1dee18..739e8a2a2d30 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -3348,7 +3348,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
case BRIDGE_W9968CF:
cam->cam_mode = w9968cf_vga_mode;
cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode);
- cam->reverse_alts = 1;
break;
}
@@ -3684,8 +3683,8 @@ static void ov511_mode_init_regs(struct sd *sd)
/* Check if we have enough bandwidth to disable compression */
fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1;
needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2;
- /* 1400 is a conservative estimate of the max nr of isoc packets/sec */
- if (needed > 1400 * packet_size) {
+ /* 1000 isoc packets/sec */
+ if (needed > 1000 * packet_size) {
/* Enable Y and UV quantization and compression */
reg_w(sd, R511_COMP_EN, 0x07);
reg_w(sd, R511_COMP_LUT_EN, 0x03);
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
index f30060d50633..e6601b886032 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -71,6 +71,7 @@ struct sd {
enum sensors {
SENSOR_OV965x, /* ov9657 */
SENSOR_OV971x, /* ov9712 */
+ SENSOR_OV562x, /* ov5621 */
NSENSORS
};
@@ -207,6 +208,14 @@ static const struct v4l2_pix_format ov971x_mode[] = {
}
};
+static const struct v4l2_pix_format ov562x_mode[] = {
+ {2592, 1680, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 2592,
+ .sizeimage = 2592 * 1680,
+ .colorspace = V4L2_COLORSPACE_SRGB
+ }
+};
+
static const u8 bridge_init[][2] = {
{0x88, 0xf8},
{0x89, 0xff},
@@ -830,6 +839,124 @@ static const u8 ov965x_start_2_sxga[][2] = {
{0xa3, 0x41}, /* bd60 */
};
+static const u8 ov562x_init[][2] = {
+ {0x88, 0x20},
+ {0x89, 0x0a},
+ {0x8a, 0x90},
+ {0x8b, 0x06},
+ {0x8c, 0x01},
+ {0x8d, 0x10},
+ {0x1c, 0x00},
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a},
+ {0x1d, 0x2e},
+ {0x1d, 0x1e},
+};
+
+static const u8 ov562x_init_2[][2] = {
+ {0x12, 0x80},
+ {0x11, 0x41},
+ {0x13, 0x00},
+ {0x10, 0x1e},
+ {0x3b, 0x07},
+ {0x5b, 0x40},
+ {0x39, 0x07},
+ {0x53, 0x02},
+ {0x54, 0x60},
+ {0x04, 0x20},
+ {0x27, 0x04},
+ {0x3d, 0x40},
+ {0x36, 0x00},
+ {0xc5, 0x04},
+ {0x4e, 0x00},
+ {0x4f, 0x93},
+ {0x50, 0x7b},
+ {0xca, 0x0c},
+ {0xcb, 0x0f},
+ {0x39, 0x07},
+ {0x4a, 0x10},
+ {0x3e, 0x0a},
+ {0x3d, 0x00},
+ {0x0c, 0x38},
+ {0x38, 0x90},
+ {0x46, 0x30},
+ {0x4f, 0x93},
+ {0x50, 0x7b},
+ {0xab, 0x00},
+ {0xca, 0x0c},
+ {0xcb, 0x0f},
+ {0x37, 0x02},
+ {0x44, 0x48},
+ {0x8d, 0x44},
+ {0x2a, 0x00},
+ {0x2b, 0x00},
+ {0x32, 0x00},
+ {0x38, 0x90},
+ {0x53, 0x02},
+ {0x54, 0x60},
+ {0x12, 0x00},
+ {0x17, 0x12},
+ {0x18, 0xb4},
+ {0x19, 0x0c},
+ {0x1a, 0xf4},
+ {0x03, 0x4a},
+ {0x89, 0x20},
+ {0x83, 0x80},
+ {0xb7, 0x9d},
+ {0xb6, 0x11},
+ {0xb5, 0x55},
+ {0xb4, 0x00},
+ {0xa9, 0xf0},
+ {0xa8, 0x0a},
+ {0xb8, 0xf0},
+ {0xb9, 0xf0},
+ {0xba, 0xf0},
+ {0x81, 0x07},
+ {0x63, 0x44},
+ {0x13, 0xc7},
+ {0x14, 0x60},
+ {0x33, 0x75},
+ {0x2c, 0x00},
+ {0x09, 0x00},
+ {0x35, 0x30},
+ {0x27, 0x04},
+ {0x3c, 0x07},
+ {0x3a, 0x0a},
+ {0x3b, 0x07},
+ {0x01, 0x40},
+ {0x02, 0x40},
+ {0x16, 0x40},
+ {0x52, 0xb0},
+ {0x51, 0x83},
+ {0x21, 0xbb},
+ {0x22, 0x10},
+ {0x23, 0x03},
+ {0x35, 0x38},
+ {0x20, 0x90},
+ {0x28, 0x30},
+ {0x73, 0xe1},
+ {0x6c, 0x00},
+ {0x6d, 0x80},
+ {0x6e, 0x00},
+ {0x70, 0x04},
+ {0x71, 0x00},
+ {0x8d, 0x04},
+ {0x64, 0x00},
+ {0x65, 0x00},
+ {0x66, 0x00},
+ {0x67, 0x00},
+ {0x68, 0x00},
+ {0x69, 0x00},
+ {0x6a, 0x00},
+ {0x6b, 0x00},
+ {0x71, 0x94},
+ {0x74, 0x20},
+ {0x80, 0x09},
+ {0x85, 0xc0},
+};
+
static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val)
{
struct usb_device *udev = gspca_dev->dev;
@@ -980,16 +1107,34 @@ static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 val;
+ s8 sval;
if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS))
return;
- val = sd->ctrls[BRIGHTNESS].val;
- if (val < 8)
- val = 15 - val; /* f .. 8 */
- else
- val = val - 8; /* 0 .. 7 */
- sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */
- 0x0f | (val << 4));
+ if (sd->sensor == SENSOR_OV562x) {
+ sval = sd->ctrls[BRIGHTNESS].val;
+ val = 0x76;
+ val += sval;
+ sccb_write(gspca_dev, 0x24, val);
+ val = 0x6a;
+ val += sval;
+ sccb_write(gspca_dev, 0x25, val);
+ if (sval < -40)
+ val = 0x71;
+ else if (sval < 20)
+ val = 0x94;
+ else
+ val = 0xe6;
+ sccb_write(gspca_dev, 0x26, val);
+ } else {
+ val = sd->ctrls[BRIGHTNESS].val;
+ if (val < 8)
+ val = 15 - val; /* f .. 8 */
+ else
+ val = val - 8; /* 0 .. 7 */
+ sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */
+ 0x0f | (val << 4));
+ }
}
static void setcontrast(struct gspca_dev *gspca_dev)
@@ -1210,6 +1355,26 @@ static int sd_init(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x56, 0x1f);
else
reg_w(gspca_dev, 0x56, 0x17);
+ } else if ((sensor_id & 0xfff0) == 0x5620) {
+ sd->sensor = SENSOR_OV562x;
+ gspca_dev->ctrl_dis = (1 << CONTRAST) |
+ (1 << AUTOGAIN) |
+ (1 << EXPOSURE) |
+ (1 << SHARPNESS) |
+ (1 << SATUR) |
+ (1 << LIGHTFREQ);
+
+ sd->ctrls[BRIGHTNESS].min = -90;
+ sd->ctrls[BRIGHTNESS].max = 90;
+ sd->ctrls[BRIGHTNESS].def = 0;
+ gspca_dev->cam.cam_mode = ov562x_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode);
+
+ reg_w_array(gspca_dev, ov562x_init,
+ ARRAY_SIZE(ov562x_init));
+ sccb_w_array(gspca_dev, ov562x_init_2,
+ ARRAY_SIZE(ov562x_init_2));
+ reg_w(gspca_dev, 0xe0, 0x00);
} else {
err("Unknown sensor %04x", sensor_id);
return -EINVAL;
@@ -1224,6 +1389,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
if (sd->sensor == SENSOR_OV971x)
return gspca_dev->usb_err;
+ else if (sd->sensor == SENSOR_OV562x) {
+ setbrightness(gspca_dev);
+ return gspca_dev->usb_err;
+ }
switch (gspca_dev->curr_mode) {
case QVGA_MODE: /* 320x240 */
sccb_w_array(gspca_dev, ov965x_start_1_vga,
@@ -1409,6 +1578,7 @@ static const struct sd_desc sd_desc = {
static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x05a9, 0x8065)},
{USB_DEVICE(0x06f8, 0x3003)},
+ {USB_DEVICE(0x05a9, 0x1550)},
{}
};
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index ece8b1e82a13..3844c49f269c 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -41,14 +41,14 @@ MODULE_LICENSE("GPL");
#define PAC207_BRIGHTNESS_DEFAULT 46
#define PAC207_EXPOSURE_MIN 3
-#define PAC207_EXPOSURE_MAX 26
+#define PAC207_EXPOSURE_MAX 90 /* 1 sec expo time / 1 fps */
#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */
-#define PAC207_EXPOSURE_KNEE 8 /* 4 = 30 fps, 11 = 8, 15 = 6 */
+#define PAC207_EXPOSURE_KNEE 9 /* fps: 90 / exposure -> 9: 10 fps */
#define PAC207_GAIN_MIN 0
#define PAC207_GAIN_MAX 31
-#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */
-#define PAC207_GAIN_KNEE 31
+#define PAC207_GAIN_DEFAULT 7 /* power on default: 9 */
+#define PAC207_GAIN_KNEE 15
#define PAC207_AUTOGAIN_DEADZONE 30
@@ -332,7 +332,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
if (sd->autogain_ignore_frames > 0)
sd->autogain_ignore_frames--;
else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
- 100, PAC207_AUTOGAIN_DEADZONE,
+ 90, PAC207_AUTOGAIN_DEADZONE,
PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
}
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index 2811195258c4..30662fccb0cf 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -1,8 +1,8 @@
/*
- * Pixart PAC7302 library
- * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ * Pixart PAC7302 driver
*
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2008-2012 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
*
* Separated from Pixart PAC7311 library by Márton Németh
* Camera button input handling by Márton Németh <nm127@freemail.hu>
@@ -63,67 +63,61 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#define MODULE_NAME "pac7302"
-
#include <linux/input.h>
#include <media/v4l2-chip-ident.h>
#include "gspca.h"
+/* Include pac common sof detection functions */
+#include "pac_common.h"
-MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
+ "Thomas Kaiser thomas@kaiser-linux.li");
MODULE_DESCRIPTION("Pixart PAC7302");
MODULE_LICENSE("GPL");
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ COLORS,
+ WHITE_BALANCE,
+ RED_BALANCE,
+ BLUE_BALANCE,
+ GAIN,
+ AUTOGAIN,
+ EXPOSURE,
+ VFLIP,
+ HFLIP,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor for pac7302 */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned char brightness;
- unsigned char contrast;
- unsigned char colors;
- unsigned char white_balance;
- unsigned char red_balance;
- unsigned char blue_balance;
- unsigned char gain;
- unsigned char autogain;
- unsigned short exposure;
- __u8 hflip;
- __u8 vflip;
+ struct gspca_ctrl ctrls[NCTRLS];
+
u8 flags;
#define FL_HFLIP 0x01 /* mirrored by default */
#define FL_VFLIP 0x02 /* vertical flipped by default */
u8 sof_read;
- u8 autogain_ignore_frames;
+ s8 autogain_ignore_frames;
atomic_t avg_lum;
};
/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightcont(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setwhitebalance(struct gspca_dev *gspca_dev);
+static void setredbalance(struct gspca_dev *gspca_dev);
+static void setbluebalance(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static void setautogain(struct gspca_dev *gspca_dev);
+static void sethvflip(struct gspca_dev *gspca_dev);
static const struct ctrl sd_ctrls[] = {
- {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -132,13 +126,11 @@ static const struct ctrl sd_ctrls[] = {
#define BRIGHTNESS_MAX 0x20
.maximum = BRIGHTNESS_MAX,
.step = 1,
-#define BRIGHTNESS_DEF 0x10
- .default_value = BRIGHTNESS_DEF,
+ .default_value = 0x10,
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = setbrightcont
},
- {
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -147,13 +139,11 @@ static const struct ctrl sd_ctrls[] = {
#define CONTRAST_MAX 255
.maximum = CONTRAST_MAX,
.step = 1,
-#define CONTRAST_DEF 127
- .default_value = CONTRAST_DEF,
+ .default_value = 127,
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = setbrightcont
},
- {
+[COLORS] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -162,13 +152,11 @@ static const struct ctrl sd_ctrls[] = {
#define COLOR_MAX 255
.maximum = COLOR_MAX,
.step = 1,
-#define COLOR_DEF 127
- .default_value = COLOR_DEF,
+ .default_value = 127
},
- .set = sd_setcolors,
- .get = sd_getcolors,
+ .set_control = setcolors
},
- {
+[WHITE_BALANCE] = {
{
.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -176,13 +164,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define WHITEBALANCE_DEF 4
- .default_value = WHITEBALANCE_DEF,
+ .default_value = 4,
},
- .set = sd_setwhitebalance,
- .get = sd_getwhitebalance,
+ .set_control = setwhitebalance
},
- {
+[RED_BALANCE] = {
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -190,13 +176,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 3,
.step = 1,
-#define REDBALANCE_DEF 1
- .default_value = REDBALANCE_DEF,
+ .default_value = 1,
},
- .set = sd_setredbalance,
- .get = sd_getredbalance,
+ .set_control = setredbalance
},
- {
+[BLUE_BALANCE] = {
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -204,29 +188,25 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 3,
.step = 1,
-#define BLUEBALANCE_DEF 1
- .default_value = BLUEBALANCE_DEF,
+ .default_value = 1,
},
- .set = sd_setbluebalance,
- .get = sd_getbluebalance,
+ .set_control = setbluebalance
},
- {
+[GAIN] = {
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
.minimum = 0,
-#define GAIN_MAX 255
- .maximum = GAIN_MAX,
+ .maximum = 255,
.step = 1,
#define GAIN_DEF 127
#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
.default_value = GAIN_DEF,
},
- .set = sd_setgain,
- .get = sd_getgain,
+ .set_control = setgain
},
- {
+[EXPOSURE] = {
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -238,10 +218,9 @@ static const struct ctrl sd_ctrls[] = {
#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
.default_value = EXPOSURE_DEF,
},
- .set = sd_setexposure,
- .get = sd_getexposure,
+ .set_control = setexposure
},
- {
+[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -252,10 +231,9 @@ static const struct ctrl sd_ctrls[] = {
#define AUTOGAIN_DEF 1
.default_value = AUTOGAIN_DEF,
},
- .set = sd_setautogain,
- .get = sd_getautogain,
+ .set_control = setautogain,
},
- {
+[HFLIP] = {
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -263,13 +241,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define HFLIP_DEF 0
- .default_value = HFLIP_DEF,
+ .default_value = 0,
},
- .set = sd_sethflip,
- .get = sd_gethflip,
+ .set_control = sethvflip,
},
- {
+[VFLIP] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -277,11 +253,9 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define VFLIP_DEF 0
- .default_value = VFLIP_DEF,
+ .default_value = 0,
},
- .set = sd_setvflip,
- .get = sd_getvflip,
+ .set_control = sethvflip
},
};
@@ -290,21 +264,21 @@ static const struct v4l2_pix_format vga_mode[] = {
.bytesperline = 640,
.sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 0},
+ },
};
#define LOAD_PAGE3 255
#define END_OF_SEQUENCE 0
/* pac 7302 */
-static const __u8 init_7302[] = {
+static const u8 init_7302[] = {
/* index,value */
0xff, 0x01, /* page 1 */
0x78, 0x00, /* deactivate */
0xff, 0x01,
0x78, 0x40, /* led off */
};
-static const __u8 start_7302[] = {
+static const u8 start_7302[] = {
/* index, len, [value]* */
0xff, 1, 0x00, /* page 0 */
0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
@@ -319,7 +293,7 @@ static const __u8 start_7302[] = {
0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
0x00, 0x54, 0x11,
0x55, 1, 0x00,
- 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
+ 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
0x6b, 1, 0x00,
0x6e, 3, 0x08, 0x06, 0x00,
0x72, 3, 0x00, 0xff, 0x00,
@@ -370,7 +344,7 @@ static const __u8 start_7302[] = {
#define SKIP 0xaa
/* page 3 - the value SKIP says skip the index - see reg_w_page() */
-static const __u8 page3_7302[] = {
+static const u8 page3_7302[] = {
0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -394,7 +368,7 @@ static const __u8 page3_7302[] = {
};
static void reg_w_buf(struct gspca_dev *gspca_dev,
- __u8 index,
+ u8 index,
const u8 *buffer, int len)
{
int ret;
@@ -410,7 +384,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
index, gspca_dev->usb_buf, len,
500);
if (ret < 0) {
- pr_err("reg_w_buf failed index 0x%02x, error %d\n",
+ pr_err("reg_w_buf failed i: %02x error %d\n",
index, ret);
gspca_dev->usb_err = ret;
}
@@ -418,8 +392,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
static void reg_w(struct gspca_dev *gspca_dev,
- __u8 index,
- __u8 value)
+ u8 index,
+ u8 value)
{
int ret;
@@ -433,14 +407,14 @@ static void reg_w(struct gspca_dev *gspca_dev,
0, index, gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
+ pr_err("reg_w() failed i: %02x v: %02x error %d\n",
index, value, ret);
gspca_dev->usb_err = ret;
}
}
static void reg_w_seq(struct gspca_dev *gspca_dev,
- const __u8 *seq, int len)
+ const u8 *seq, int len)
{
while (--len >= 0) {
reg_w(gspca_dev, seq[0], seq[1]);
@@ -450,7 +424,7 @@ static void reg_w_seq(struct gspca_dev *gspca_dev,
/* load the beginning of a page */
static void reg_w_page(struct gspca_dev *gspca_dev,
- const __u8 *page, int len)
+ const u8 *page, int len)
{
int index;
int ret = 0;
@@ -468,7 +442,7 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
0, index, gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
+ pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
index, page[index], ret);
gspca_dev->usb_err = ret;
break;
@@ -478,8 +452,8 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
/* output a variable sequence */
static void reg_w_var(struct gspca_dev *gspca_dev,
- const __u8 *seq,
- const __u8 *page3, unsigned int page3_len)
+ const u8 *seq,
+ const u8 *page3, unsigned int page3_len)
{
int index, len;
@@ -493,11 +467,13 @@ static void reg_w_var(struct gspca_dev *gspca_dev,
reg_w_page(gspca_dev, page3, page3_len);
break;
default:
+#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
PDEBUG(D_ERR|D_STREAM,
"Incorrect variable sequence");
return;
}
+#endif
while (len > 0) {
if (len < 8) {
reg_w_buf(gspca_dev,
@@ -524,21 +500,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
- PDEBUG(D_CONF, "Find Sensor PAC7302");
cam->cam_mode = vga_mode; /* only 640x480 */
cam->nmodes = ARRAY_SIZE(vga_mode);
- sd->brightness = BRIGHTNESS_DEF;
- sd->contrast = CONTRAST_DEF;
- sd->colors = COLOR_DEF;
- sd->white_balance = WHITEBALANCE_DEF;
- sd->red_balance = REDBALANCE_DEF;
- sd->blue_balance = BLUEBALANCE_DEF;
- sd->gain = GAIN_DEF;
- sd->exposure = EXPOSURE_DEF;
- sd->autogain = AUTOGAIN_DEF;
- sd->hflip = HFLIP_DEF;
- sd->vflip = VFLIP_DEF;
+ gspca_dev->cam.ctrls = sd->ctrls;
+
sd->flags = id->driver_info;
return 0;
}
@@ -548,19 +514,19 @@ static void setbrightcont(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i, v;
- static const __u8 max[10] =
+ static const u8 max[10] =
{0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
0xd4, 0xec};
- static const __u8 delta[10] =
+ static const u8 delta[10] =
{0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
0x11, 0x0b};
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
for (i = 0; i < 10; i++) {
v = max[i];
- v += (sd->brightness - BRIGHTNESS_MAX)
+ v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX)
* 150 / BRIGHTNESS_MAX; /* 200 ? */
- v -= delta[i] * sd->contrast / CONTRAST_MAX;
+ v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX;
if (v < 0)
v = 0;
else if (v > 0xff)
@@ -584,12 +550,11 @@ static void setcolors(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x11, 0x01);
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
for (i = 0; i < 9; i++) {
- v = a[i] * sd->colors / COLOR_MAX + b[i];
+ v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i];
reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
}
reg_w(gspca_dev, 0xdc, 0x01);
- PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
}
static void setwhitebalance(struct gspca_dev *gspca_dev)
@@ -597,10 +562,9 @@ static void setwhitebalance(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- reg_w(gspca_dev, 0xc6, sd->white_balance);
+ reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val);
reg_w(gspca_dev, 0xdc, 0x01);
- PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
}
static void setredbalance(struct gspca_dev *gspca_dev)
@@ -608,10 +572,9 @@ static void setredbalance(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- reg_w(gspca_dev, 0xc5, sd->red_balance);
+ reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val);
reg_w(gspca_dev, 0xdc, 0x01);
- PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
}
static void setbluebalance(struct gspca_dev *gspca_dev)
@@ -619,10 +582,9 @@ static void setbluebalance(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- reg_w(gspca_dev, 0xc7, sd->blue_balance);
+ reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val);
reg_w(gspca_dev, 0xdc, 0x01);
- PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
}
static void setgain(struct gspca_dev *gspca_dev)
@@ -630,7 +592,7 @@ static void setgain(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
- reg_w(gspca_dev, 0x10, sd->gain >> 3);
+ reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
@@ -639,13 +601,13 @@ static void setgain(struct gspca_dev *gspca_dev)
static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 clockdiv;
- __u16 exposure;
+ u8 clockdiv;
+ u16 exposure;
/* register 2 of frame 3 contains the clock divider configuring the
no fps according to the formula: 90 / reg. sd->exposure is the
desired exposure time in 0.5 ms. */
- clockdiv = (90 * sd->exposure + 1999) / 2000;
+ clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000;
/* Note clockdiv = 3 also works, but when running at 30 fps, depending
on the scene being recorded, the camera switches to another
@@ -664,7 +626,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
/* frame exposure time in ms = 1000 * clockdiv / 90 ->
exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
- exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv);
+ exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv);
/* 0 = use full frametime, 448 = no exposure, reverse it */
exposure = 448 - exposure;
@@ -677,15 +639,35 @@ static void setexposure(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x11, 0x01);
}
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* when switching to autogain set defaults to make sure
+ we are on a valid point of the autogain gain /
+ exposure knee graph, and give this change time to
+ take effect before doing autogain. */
+ if (sd->ctrls[AUTOGAIN].val) {
+ sd->ctrls[EXPOSURE].val = EXPOSURE_DEF;
+ sd->ctrls[GAIN].val = GAIN_DEF;
+ sd->autogain_ignore_frames =
+ PAC_AUTOGAIN_IGNORE_FRAMES;
+ } else {
+ sd->autogain_ignore_frames = -1;
+ }
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+}
+
static void sethvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 data, hflip, vflip;
- hflip = sd->hflip;
+ hflip = sd->ctrls[HFLIP].val;
if (sd->flags & FL_HFLIP)
hflip = !hflip;
- vflip = sd->vflip;
+ vflip = sd->ctrls[VFLIP].val;
if (sd->flags & FL_VFLIP)
vflip = !vflip;
@@ -708,8 +690,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->sof_read = 0;
-
reg_w_var(gspca_dev, start_7302,
page3_7302, sizeof(page3_7302));
setbrightcont(gspca_dev);
@@ -717,15 +697,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
setwhitebalance(gspca_dev);
setredbalance(gspca_dev);
setbluebalance(gspca_dev);
- setgain(gspca_dev);
- setexposure(gspca_dev);
+ setautogain(gspca_dev);
sethvflip(gspca_dev);
/* only resolution 640x480 is supported for pac7302 */
sd->sof_read = 0;
- sd->autogain_ignore_frames = 0;
- atomic_set(&sd->avg_lum, -1);
+ atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val);
/* start stream */
reg_w(gspca_dev, 0xff, 0x01);
@@ -751,8 +729,10 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x78, 0x40);
}
-/* Include pac common sof detection functions */
-#include "pac_common.h"
+/* !! coarse_grained_expo_autogain is not used !! */
+#define exp_too_low_cnt flags
+#define exp_too_high_cnt sof_read
+#include "autogain_functions.h"
static void do_autogain(struct gspca_dev *gspca_dev)
{
@@ -761,65 +741,44 @@ static void do_autogain(struct gspca_dev *gspca_dev)
int desired_lum;
const int deadzone = 30;
- if (avg_lum == -1)
+ if (sd->autogain_ignore_frames < 0)
return;
- desired_lum = 270 + sd->brightness;
-
- if (sd->autogain_ignore_frames > 0)
+ if (sd->autogain_ignore_frames > 0) {
sd->autogain_ignore_frames--;
- else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
- deadzone, GAIN_KNEE, EXPOSURE_KNEE))
+ } else {
+ desired_lum = 270 + sd->ctrls[BRIGHTNESS].val;
+
+ auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+ deadzone, GAIN_KNEE, EXPOSURE_KNEE);
sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
+ }
}
-/* JPEG header, part 1 */
-static const unsigned char pac_jpeg_header1[] = {
- 0xff, 0xd8, /* SOI: Start of Image */
-
- 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
- 0x00, 0x11, /* length = 17 bytes (including this length field) */
- 0x08 /* Precision: 8 */
- /* 2 bytes is placed here: number of image lines */
- /* 2 bytes is placed here: samples per line */
-};
-
-/* JPEG header, continued */
-static const unsigned char pac_jpeg_header2[] = {
- 0x03, /* Number of image components: 3 */
- 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
- 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
- 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
-
- 0xff, 0xda, /* SOS: Start Of Scan */
- 0x00, 0x0c, /* length = 12 bytes (including this length field) */
- 0x03, /* number of components: 3 */
- 0x01, 0x00, /* selector 1, table 0x00 */
- 0x02, 0x11, /* selector 2, table 0x11 */
- 0x03, 0x11, /* selector 3, table 0x11 */
- 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
- 0x00 /* Successive approximation: 0 */
+/* JPEG header */
+static const u8 jpeg_header[] = {
+ 0xff, 0xd8, /* SOI: Start of Image */
+
+ 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
+ 0x00, 0x11, /* length = 17 bytes (including this length field) */
+ 0x08, /* Precision: 8 */
+ 0x02, 0x80, /* height = 640 (image rotated) */
+ 0x01, 0xe0, /* width = 480 */
+ 0x03, /* Number of image components: 3 */
+ 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
+ 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
+ 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
+
+ 0xff, 0xda, /* SOS: Start Of Scan */
+ 0x00, 0x0c, /* length = 12 bytes (including this length field) */
+ 0x03, /* number of components: 3 */
+ 0x01, 0x00, /* selector 1, table 0x00 */
+ 0x02, 0x11, /* selector 2, table 0x11 */
+ 0x03, 0x11, /* selector 3, table 0x11 */
+ 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
+ 0x00 /* Successive approximation: 0 */
};
-static void pac_start_frame(struct gspca_dev *gspca_dev,
- __u16 lines, __u16 samples_per_line)
-{
- unsigned char tmpbuf[4];
-
- gspca_frame_add(gspca_dev, FIRST_PACKET,
- pac_jpeg_header1, sizeof(pac_jpeg_header1));
-
- tmpbuf[0] = lines >> 8;
- tmpbuf[1] = lines & 0xff;
- tmpbuf[2] = samples_per_line >> 8;
- tmpbuf[3] = samples_per_line & 0xff;
-
- gspca_frame_add(gspca_dev, INTER_PACKET,
- tmpbuf, sizeof(tmpbuf));
- gspca_frame_add(gspca_dev, INTER_PACKET,
- pac_jpeg_header2, sizeof(pac_jpeg_header2));
-}
-
/* this function is run at interrupt level */
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
@@ -827,7 +786,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
u8 *image;
- unsigned char *sof;
+ u8 *sof;
sof = pac_find_sof(&sd->sof_read, data, len);
if (sof) {
@@ -864,234 +823,21 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
n >= lum_offset)
atomic_set(&sd->avg_lum, data[-lum_offset] +
data[-lum_offset + 1]);
- else
- atomic_set(&sd->avg_lum, -1);
/* Start the new frame with the jpeg header */
/* The PAC7302 has the image rotated 90 degrees */
- pac_start_frame(gspca_dev,
- gspca_dev->width, gspca_dev->height);
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ jpeg_header, sizeof jpeg_header);
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- setbrightcont(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->brightness;
- return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->contrast = val;
- if (gspca_dev->streaming)
- setbrightcont(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->colors = val;
- if (gspca_dev->streaming)
- setcolors(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->colors;
- return 0;
-}
-
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->white_balance = val;
- if (gspca_dev->streaming)
- setwhitebalance(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->white_balance;
- return 0;
-}
-
-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->red_balance = val;
- if (gspca_dev->streaming)
- setredbalance(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->red_balance;
- return 0;
-}
-
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->blue_balance = val;
- if (gspca_dev->streaming)
- setbluebalance(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->blue_balance;
- return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gain = val;
- if (gspca_dev->streaming)
- setgain(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->gain;
- return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->exposure = val;
- if (gspca_dev->streaming)
- setexposure(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->exposure;
- return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->autogain = val;
- /* when switching to autogain set defaults to make sure
- we are on a valid point of the autogain gain /
- exposure knee graph, and give this change time to
- take effect before doing autogain. */
- if (sd->autogain) {
- sd->exposure = EXPOSURE_DEF;
- sd->gain = GAIN_DEF;
- if (gspca_dev->streaming) {
- sd->autogain_ignore_frames =
- PAC_AUTOGAIN_IGNORE_FRAMES;
- setexposure(gspca_dev);
- setgain(gspca_dev);
- }
- }
-
- return gspca_dev->usb_err;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->autogain;
- return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->hflip = val;
- if (gspca_dev->streaming)
- sethvflip(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->hflip;
- return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->vflip = val;
- if (gspca_dev->streaming)
- sethvflip(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->vflip;
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
struct v4l2_dbg_register *reg)
{
- __u8 index;
- __u8 value;
+ u8 index;
+ u8 value;
/* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
long on the USB bus)
@@ -1103,8 +849,8 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
) {
/* Currently writing to page 0 is only supported. */
/* reg_w() only supports 8bit index */
- index = reg->reg & 0x000000ff;
- value = reg->val & 0x000000ff;
+ index = reg->reg;
+ value = reg->val;
/* Note that there shall be no access to other page
by any other function between the page swith and
@@ -1165,7 +911,7 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
/* sub-driver description for pac7302 */
static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
@@ -1187,6 +933,7 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x06f8, 0x3009)},
+ {USB_DEVICE(0x06f8, 0x301b)},
{USB_DEVICE(0x093a, 0x2620)},
{USB_DEVICE(0x093a, 0x2621)},
{USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
@@ -1197,6 +944,7 @@ static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
{USB_DEVICE(0x093a, 0x262a)},
{USB_DEVICE(0x093a, 0x262c)},
+ {USB_DEVICE(0x145f, 0x013c)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
@@ -1210,7 +958,7 @@ static int sd_probe(struct usb_interface *intf,
}
static struct usb_driver sd_driver = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/video/gspca/se401.c
index 1494e1829d36..bb70092c2229 100644
--- a/drivers/media/video/gspca/se401.c
+++ b/drivers/media/video/gspca/se401.c
@@ -376,7 +376,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->bulk_size = BULK_SIZE;
cam->bulk_nurbs = 4;
cam->ctrls = sd->ctrls;
- gspca_dev->nbalt = 1; /* Ignore the bogus isoc alt settings */
sd->resetlevel = 0x2d; /* Set initial resetlevel */
/* See if the camera supports brightness */
@@ -395,6 +394,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
return 0;
}
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ gspca_dev->alt = 1; /* Ignore the bogus isoc alt settings */
+
+ return gspca_dev->usb_err;
+}
+
/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
@@ -714,6 +721,7 @@ static const struct sd_desc sd_desc = {
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
+ .isoc_init = sd_isoc_init,
.start = sd_start,
.stopN = sd_stopN,
.dq_callback = sd_dq_callback,
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 33cabc342dcf..7e71aa2d2522 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -1,5 +1,7 @@
/*
* Sonix sn9c201 sn9c202 library
+ *
+ * Copyright (C) 2012 Jean-Francois Moine <http://moinejf.free.fr>
* Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
* Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
*
@@ -33,8 +35,6 @@ MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
MODULE_LICENSE("GPL");
-#define MODULE_NAME "sn9c20x"
-
/*
* Pixel format private data
*/
@@ -66,10 +66,37 @@ MODULE_LICENSE("GPL");
#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
#define FLIP_DETECT 0x4
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ SATURATION,
+ HUE,
+ GAMMA,
+ BLUE,
+ RED,
+ VFLIP,
+ HFLIP,
+ EXPOSURE,
+ GAIN,
+ AUTOGAIN,
+ QUALITY,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev;
+ struct gspca_ctrl ctrls[NCTRLS];
+
+ struct work_struct work;
+ struct workqueue_struct *work_thread;
+
+ u32 pktsz; /* (used by pkt_scan) */
+ u16 npkt;
+ s8 nchg;
+ u8 fmt; /* (used for JPEG QTAB update */
+
#define MIN_AVG_LUM 80
#define MAX_AVG_LUM 130
atomic_t avg_lum;
@@ -77,31 +104,18 @@ struct sd {
u8 older_step;
u8 exposure_step;
- u8 brightness;
- u8 contrast;
- u8 saturation;
- s16 hue;
- u8 gamma;
- u8 red;
- u8 blue;
-
- u8 hflip;
- u8 vflip;
- u8 gain;
- u16 exposure;
- u8 auto_exposure;
-
u8 i2c_addr;
u8 sensor;
u8 hstart;
u8 vstart;
u8 jpeg_hdr[JPEG_HDR_SZ];
- u8 quality;
u8 flags;
};
+static void qual_upd(struct work_struct *work);
+
struct i2c_reg_u8 {
u8 reg;
u8 val;
@@ -112,31 +126,6 @@ struct i2c_reg_u16 {
u16 val;
};
-static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_sethue(struct gspca_dev *gspca_dev, s32 val);
-static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
-
static const struct dmi_system_id flip_dmi_table[] = {
{
.ident = "MSI MS-1034",
@@ -177,9 +166,16 @@ static const struct dmi_system_id flip_dmi_table[] = {
{}
};
-static const struct ctrl sd_ctrls[] = {
- {
-#define BRIGHTNESS_IDX 0
+static void set_cmatrix(struct gspca_dev *gspca_dev);
+static void set_gamma(struct gspca_dev *gspca_dev);
+static void set_redblue(struct gspca_dev *gspca_dev);
+static void set_hvflip(struct gspca_dev *gspca_dev);
+static void set_exposure(struct gspca_dev *gspca_dev);
+static void set_gain(struct gspca_dev *gspca_dev);
+static void set_quality(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -187,14 +183,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define BRIGHTNESS_DEFAULT 0x7f
- .default_value = BRIGHTNESS_DEFAULT,
+ .default_value = 0x7f
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = set_cmatrix
},
- {
-#define CONTRAST_IDX 1
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -202,14 +195,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define CONTRAST_DEFAULT 0x7f
- .default_value = CONTRAST_DEFAULT,
+ .default_value = 0x7f
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = set_cmatrix
},
- {
-#define SATURATION_IDX 2
+[SATURATION] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -217,14 +207,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define SATURATION_DEFAULT 0x7f
- .default_value = SATURATION_DEFAULT,
+ .default_value = 0x7f
},
- .set = sd_setsaturation,
- .get = sd_getsaturation,
+ .set_control = set_cmatrix
},
- {
-#define HUE_IDX 3
+[HUE] = {
{
.id = V4L2_CID_HUE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -232,14 +219,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = -180,
.maximum = 180,
.step = 1,
-#define HUE_DEFAULT 0
- .default_value = HUE_DEFAULT,
+ .default_value = 0
},
- .set = sd_sethue,
- .get = sd_gethue,
+ .set_control = set_cmatrix
},
- {
-#define GAMMA_IDX 4
+[GAMMA] = {
{
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -247,14 +231,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define GAMMA_DEFAULT 0x10
- .default_value = GAMMA_DEFAULT,
+ .default_value = 0x10
},
- .set = sd_setgamma,
- .get = sd_getgamma,
+ .set_control = set_gamma
},
- {
-#define BLUE_IDX 5
+[BLUE] = {
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -262,14 +243,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0x7f,
.step = 1,
-#define BLUE_DEFAULT 0x28
- .default_value = BLUE_DEFAULT,
+ .default_value = 0x28
},
- .set = sd_setbluebalance,
- .get = sd_getbluebalance,
+ .set_control = set_redblue
},
- {
-#define RED_IDX 6
+[RED] = {
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -277,14 +255,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0x7f,
.step = 1,
-#define RED_DEFAULT 0x28
- .default_value = RED_DEFAULT,
+ .default_value = 0x28
},
- .set = sd_setredbalance,
- .get = sd_getredbalance,
+ .set_control = set_redblue
},
- {
-#define HFLIP_IDX 7
+[HFLIP] = {
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -292,14 +267,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define HFLIP_DEFAULT 0
- .default_value = HFLIP_DEFAULT,
+ .default_value = 0,
},
- .set = sd_sethflip,
- .get = sd_gethflip,
+ .set_control = set_hvflip
},
- {
-#define VFLIP_IDX 8
+[VFLIP] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -307,14 +279,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define VFLIP_DEFAULT 0
- .default_value = VFLIP_DEFAULT,
+ .default_value = 0,
},
- .set = sd_setvflip,
- .get = sd_getvflip,
+ .set_control = set_hvflip
},
- {
-#define EXPOSURE_IDX 9
+[EXPOSURE] = {
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -322,14 +291,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0x1780,
.step = 1,
-#define EXPOSURE_DEFAULT 0x33
- .default_value = EXPOSURE_DEFAULT,
+ .default_value = 0x33,
},
- .set = sd_setexposure,
- .get = sd_getexposure,
+ .set_control = set_exposure
},
- {
-#define GAIN_IDX 10
+[GAIN] = {
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -337,14 +303,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 28,
.step = 1,
-#define GAIN_DEFAULT 0x00
- .default_value = GAIN_DEFAULT,
+ .default_value = 0,
},
- .set = sd_setgain,
- .get = sd_getgain,
+ .set_control = set_gain
},
- {
-#define AUTOGAIN_IDX 11
+[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -352,11 +315,23 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define AUTO_EXPOSURE_DEFAULT 1
- .default_value = AUTO_EXPOSURE_DEFAULT,
+ .default_value = 1,
+ },
+ },
+[QUALITY] = {
+ {
+ .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Compression Quality",
+#define QUALITY_MIN 50
+#define QUALITY_MAX 90
+#define QUALITY_DEF 80
+ .minimum = QUALITY_MIN,
+ .maximum = QUALITY_MAX,
+ .step = 1,
+ .default_value = QUALITY_DEF,
},
- .set = sd_setautoexposure,
- .get = sd_getautoexposure,
+ .set_control = set_quality
},
};
@@ -876,7 +851,7 @@ static u8 hv7131r_gain[] = {
};
static struct i2c_reg_u8 soi968_init[] = {
- {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
+ {0x0c, 0x00}, {0x0f, 0x1f},
{0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
{0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
{0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
@@ -902,7 +877,7 @@ static struct i2c_reg_u8 ov7660_init[] = {
};
static struct i2c_reg_u8 ov7670_init[] = {
- {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
+ {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
{0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
{0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
{0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
@@ -959,7 +934,7 @@ static struct i2c_reg_u8 ov7670_init[] = {
};
static struct i2c_reg_u8 ov9650_init[] = {
- {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
+ {0x00, 0x00}, {0x01, 0x78},
{0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
{0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
{0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
@@ -989,7 +964,7 @@ static struct i2c_reg_u8 ov9650_init[] = {
};
static struct i2c_reg_u8 ov9655_init[] = {
- {0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
+ {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
{0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
{0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
{0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
@@ -1112,10 +1087,13 @@ static struct i2c_reg_u8 hv7131r_init[] = {
{0x23, 0x09}, {0x01, 0x08},
};
-static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
+static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
{
struct usb_device *dev = gspca_dev->dev;
int result;
+
+ if (gspca_dev->usb_err < 0)
+ return;
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
0x00,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1125,17 +1103,19 @@ static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
length,
500);
if (unlikely(result < 0 || result != length)) {
- pr_err("Read register failed 0x%02X\n", reg);
- return -EIO;
+ pr_err("Read register %02x failed %d\n", reg, result);
+ gspca_dev->usb_err = result;
}
- return 0;
}
-static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
+static void reg_w(struct gspca_dev *gspca_dev, u16 reg,
const u8 *buffer, int length)
{
struct usb_device *dev = gspca_dev->dev;
int result;
+
+ if (gspca_dev->usb_err < 0)
+ return;
memcpy(gspca_dev->usb_buf, buffer, length);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
0x08,
@@ -1146,38 +1126,41 @@ static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
length,
500);
if (unlikely(result < 0 || result != length)) {
- pr_err("Write register failed index 0x%02X\n", reg);
- return -EIO;
+ pr_err("Write register %02x failed %d\n", reg, result);
+ gspca_dev->usb_err = result;
}
- return 0;
}
-static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
+static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
{
- u8 data[1] = {value};
- return reg_w(gspca_dev, reg, data, 1);
+ reg_w(gspca_dev, reg, &value, 1);
}
-static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
+static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
{
int i;
+
reg_w(gspca_dev, 0x10c0, buffer, 8);
for (i = 0; i < 5; i++) {
reg_r(gspca_dev, 0x10c0, 1);
+ if (gspca_dev->usb_err < 0)
+ return;
if (gspca_dev->usb_buf[0] & 0x04) {
- if (gspca_dev->usb_buf[0] & 0x08)
- return -EIO;
- return 0;
+ if (gspca_dev->usb_buf[0] & 0x08) {
+ pr_err("i2c_w error\n");
+ gspca_dev->usb_err = -EIO;
+ }
+ return;
}
- msleep(1);
+ msleep(10);
}
- return -EIO;
+ pr_err("i2c_w reg %02x no response\n", buffer[2]);
+/* gspca_dev->usb_err = -EIO; fixme: may occur */
}
-static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
{
struct sd *sd = (struct sd *) gspca_dev;
-
u8 row[8];
/*
@@ -1193,10 +1176,19 @@ static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
row[6] = 0x00;
row[7] = 0x10;
- return i2c_w(gspca_dev, row);
+ i2c_w(gspca_dev, row);
+}
+
+static void i2c_w1_buf(struct gspca_dev *gspca_dev,
+ struct i2c_reg_u8 *buf, int sz)
+{
+ while (--sz >= 0) {
+ i2c_w1(gspca_dev, buf->reg, buf->val);
+ buf++;
+ }
}
-static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
+static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
@@ -1208,16 +1200,25 @@ static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
row[0] = 0x81 | (3 << 4);
row[1] = sd->i2c_addr;
row[2] = reg;
- row[3] = (val >> 8) & 0xff;
- row[4] = val & 0xff;
+ row[3] = val >> 8;
+ row[4] = val;
row[5] = 0x00;
row[6] = 0x00;
row[7] = 0x10;
- return i2c_w(gspca_dev, row);
+ i2c_w(gspca_dev, row);
}
-static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
+static void i2c_w2_buf(struct gspca_dev *gspca_dev,
+ struct i2c_reg_u16 *buf, int sz)
+{
+ while (--sz >= 0) {
+ i2c_w2(gspca_dev, buf->reg, buf->val);
+ buf++;
+ }
+}
+
+static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
@@ -1230,19 +1231,15 @@ static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
row[5] = 0;
row[6] = 0;
row[7] = 0x10;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
row[0] = 0x81 | (1 << 4) | 0x02;
row[2] = 0;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
- if (reg_r(gspca_dev, 0x10c2, 5) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
+ reg_r(gspca_dev, 0x10c2, 5);
*val = gspca_dev->usb_buf[4];
- return 0;
}
-static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
+static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
@@ -1255,233 +1252,204 @@ static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
row[5] = 0;
row[6] = 0;
row[7] = 0x10;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
row[0] = 0x81 | (2 << 4) | 0x02;
row[2] = 0;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
- if (reg_r(gspca_dev, 0x10c2, 5) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
+ reg_r(gspca_dev, 0x10c2, 5);
*val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
- return 0;
}
-static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
+static void ov9650_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
u16 id;
struct sd *sd = (struct sd *) gspca_dev;
- if (i2c_r2(gspca_dev, 0x1c, &id) < 0)
- return -EINVAL;
+ i2c_r2(gspca_dev, 0x1c, &id);
+ if (gspca_dev->usb_err < 0)
+ return;
if (id != 0x7fa2) {
pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
- return -ENODEV;
+ gspca_dev->usb_err = -ENODEV;
+ return;
}
- for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
- if (i2c_w1(gspca_dev, ov9650_init[i].reg,
- ov9650_init[i].val) < 0) {
- pr_err("OV9650 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV9650 sensor initialization failed\n");
sd->hstart = 1;
sd->vstart = 7;
- return 0;
}
-static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
+static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
- if (i2c_w1(gspca_dev, ov9655_init[i].reg,
- ov9655_init[i].val) < 0) {
- pr_err("OV9655 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV9655 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 1;
sd->vstart = 2;
- return 0;
}
-static int soi968_init_sensor(struct gspca_dev *gspca_dev)
+static void soi968_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
- if (i2c_w1(gspca_dev, soi968_init[i].reg,
- soi968_init[i].val) < 0) {
- pr_err("SOI968 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("SOI968 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX)
- | (1 << EXPOSURE_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP)
+ | (1 << EXPOSURE);
sd->hstart = 60;
sd->vstart = 11;
- return 0;
}
-static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
+static void ov7660_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
- if (i2c_w1(gspca_dev, ov7660_init[i].reg,
- ov7660_init[i].val) < 0) {
- pr_err("OV7660 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV7660 sensor initialization failed\n");
sd->hstart = 3;
sd->vstart = 3;
- return 0;
}
-static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
+static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
- if (i2c_w1(gspca_dev, ov7670_init[i].reg,
- ov7670_init[i].val) < 0) {
- pr_err("OV7670 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV7670 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 0;
sd->vstart = 1;
- return 0;
}
-static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
u16 value;
- int ret;
sd->i2c_addr = 0x5d;
- ret = i2c_r2(gspca_dev, 0xff, &value);
- if ((ret == 0) && (value == 0x8243)) {
- for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
- if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
- mt9v011_init[i].val) < 0) {
- pr_err("MT9V011 sensor initialization failed\n");
- return -ENODEV;
- }
+ i2c_r2(gspca_dev, 0xff, &value);
+ if (gspca_dev->usb_err >= 0
+ && value == 0x8243) {
+ i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init));
+ if (gspca_dev->usb_err < 0) {
+ pr_err("MT9V011 sensor initialization failed\n");
+ return;
}
sd->hstart = 2;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V011;
pr_info("MT9V011 sensor detected\n");
- return 0;
+ return;
}
+ gspca_dev->usb_err = 0;
sd->i2c_addr = 0x5c;
i2c_w2(gspca_dev, 0x01, 0x0004);
- ret = i2c_r2(gspca_dev, 0xff, &value);
- if ((ret == 0) && (value == 0x823a)) {
- for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
- if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
- mt9v111_init[i].val) < 0) {
- pr_err("MT9V111 sensor initialization failed\n");
- return -ENODEV;
- }
+ i2c_r2(gspca_dev, 0xff, &value);
+ if (gspca_dev->usb_err >= 0
+ && value == 0x823a) {
+ i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init));
+ if (gspca_dev->usb_err < 0) {
+ pr_err("MT9V111 sensor initialization failed\n");
+ return;
}
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX)
- | (1 << AUTOGAIN_IDX)
- | (1 << GAIN_IDX);
+ gspca_dev->ctrl_dis = (1 << EXPOSURE)
+ | (1 << AUTOGAIN)
+ | (1 << GAIN);
sd->hstart = 2;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V111;
pr_info("MT9V111 sensor detected\n");
- return 0;
+ return;
}
+ gspca_dev->usb_err = 0;
sd->i2c_addr = 0x5d;
- ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
- if (ret < 0) {
+ i2c_w2(gspca_dev, 0xf0, 0x0000);
+ if (gspca_dev->usb_err < 0) {
+ gspca_dev->usb_err = 0;
sd->i2c_addr = 0x48;
i2c_w2(gspca_dev, 0xf0, 0x0000);
}
- ret = i2c_r2(gspca_dev, 0x00, &value);
- if ((ret == 0) && (value == 0x1229)) {
- for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
- if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
- mt9v112_init[i].val) < 0) {
- pr_err("MT9V112 sensor initialization failed\n");
- return -ENODEV;
- }
+ i2c_r2(gspca_dev, 0x00, &value);
+ if (gspca_dev->usb_err >= 0
+ && value == 0x1229) {
+ i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init));
+ if (gspca_dev->usb_err < 0) {
+ pr_err("MT9V112 sensor initialization failed\n");
+ return;
}
sd->hstart = 6;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V112;
pr_info("MT9V112 sensor detected\n");
- return 0;
+ return;
}
- return -ENODEV;
+ gspca_dev->usb_err = -ENODEV;
}
-static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
- for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
- if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
- mt9m112_init[i].val) < 0) {
- pr_err("MT9M112 sensor initialization failed\n");
- return -ENODEV;
- }
- }
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
- | (1 << GAIN_IDX);
+
+ i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("MT9M112 sensor initialization failed\n");
+
+ gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
+ | (1 << GAIN);
sd->hstart = 0;
sd->vstart = 2;
- return 0;
}
-static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
- for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
- if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
- mt9m111_init[i].val) < 0) {
- pr_err("MT9M111 sensor initialization failed\n");
- return -ENODEV;
- }
- }
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
- | (1 << GAIN_IDX);
+
+ i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("MT9M111 sensor initialization failed\n");
+
+ gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
+ | (1 << GAIN);
sd->hstart = 0;
sd->vstart = 2;
- return 0;
}
-static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
u16 id;
- if (i2c_r2(gspca_dev, 0x00, &id) < 0)
- return -EINVAL;
+ i2c_r2(gspca_dev, 0x00, &id);
+ if (gspca_dev->usb_err < 0)
+ return;
/* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
switch (id) {
@@ -1494,85 +1462,78 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
break;
default:
pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
- return -ENODEV;
+ gspca_dev->usb_err = -ENODEV;
+ return;
}
- for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
- if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
- mt9m001_init[i].val) < 0) {
- pr_err("MT9M001 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("MT9M001 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 1;
sd->vstart = 1;
- return 0;
}
-static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
+static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
- if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
- hv7131r_init[i].val) < 0) {
- pr_err("HV7131R Sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("HV7131R Sensor initialization failed\n");
+
sd->hstart = 0;
sd->vstart = 1;
- return 0;
}
-static int set_cmatrix(struct gspca_dev *gspca_dev)
+static void set_cmatrix(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 hue_coord, hue_index = 180 + sd->hue;
+ int satur;
+ s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val;
u8 cmatrix[21];
memset(cmatrix, 0, sizeof cmatrix);
- cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
+ cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26;
cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
- cmatrix[18] = sd->brightness - 0x80;
+ cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80;
- hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
+ satur = sd->ctrls[SATURATION].val;
+ hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
cmatrix[6] = hue_coord;
cmatrix[7] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_red_y[hue_index] * satur) >> 8;
cmatrix[8] = hue_coord;
cmatrix[9] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_green_x[hue_index] * satur) >> 8;
cmatrix[10] = hue_coord;
cmatrix[11] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_green_y[hue_index] * satur) >> 8;
cmatrix[12] = hue_coord;
cmatrix[13] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_blue_x[hue_index] * satur) >> 8;
cmatrix[14] = hue_coord;
cmatrix[15] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_blue_y[hue_index] * satur) >> 8;
cmatrix[16] = hue_coord;
cmatrix[17] = (hue_coord >> 8) & 0x0f;
- return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
+ reg_w(gspca_dev, 0x10e1, cmatrix, 21);
}
-static int set_gamma(struct gspca_dev *gspca_dev)
+static void set_gamma(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 gamma[17];
- u8 gval = sd->gamma * 0xb8 / 0x100;
-
+ u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100;
gamma[0] = 0x0a;
gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
@@ -1592,29 +1553,29 @@ static int set_gamma(struct gspca_dev *gspca_dev)
gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
gamma[16] = 0xf5;
- return reg_w(gspca_dev, 0x1190, gamma, 17);
+ reg_w(gspca_dev, 0x1190, gamma, 17);
}
-static int set_redblue(struct gspca_dev *gspca_dev)
+static void set_redblue(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w1(gspca_dev, 0x118c, sd->red);
- reg_w1(gspca_dev, 0x118f, sd->blue);
- return 0;
+
+ reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val);
+ reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val);
}
-static int set_hvflip(struct gspca_dev *gspca_dev)
+static void set_hvflip(struct gspca_dev *gspca_dev)
{
u8 value, tslb, hflip, vflip;
u16 value2;
struct sd *sd = (struct sd *) gspca_dev;
if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
- hflip = !sd->hflip;
- vflip = !sd->vflip;
+ hflip = !sd->ctrls[HFLIP].val;
+ vflip = !sd->ctrls[VFLIP].val;
} else {
- hflip = sd->hflip;
- vflip = sd->vflip;
+ hflip = sd->ctrls[HFLIP].val;
+ vflip = sd->ctrls[VFLIP].val;
}
switch (sd->sensor) {
@@ -1625,8 +1586,9 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
if (vflip) {
value |= 0x10;
sd->vstart = 2;
- } else
+ } else {
sd->vstart = 3;
+ }
reg_w1(gspca_dev, 0x1182, sd->vstart);
i2c_w1(gspca_dev, 0x1e, value);
break;
@@ -1674,13 +1636,15 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
i2c_w1(gspca_dev, 0x01, value);
break;
}
- return 0;
}
-static int set_exposure(struct gspca_dev *gspca_dev)
+static void set_exposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
+ int expo;
+
+ expo = sd->ctrls[EXPOSURE].val;
switch (sd->sensor) {
case SENSOR_OV7660:
case SENSOR_OV7670:
@@ -1688,35 +1652,37 @@ static int set_exposure(struct gspca_dev *gspca_dev)
case SENSOR_OV9650:
exp[0] |= (3 << 4);
exp[2] = 0x2d;
- exp[3] = sd->exposure & 0xff;
- exp[4] = sd->exposure >> 8;
+ exp[3] = expo;
+ exp[4] = expo >> 8;
break;
case SENSOR_MT9M001:
case SENSOR_MT9V112:
case SENSOR_MT9V011:
exp[0] |= (3 << 4);
exp[2] = 0x09;
- exp[3] = sd->exposure >> 8;
- exp[4] = sd->exposure & 0xff;
+ exp[3] = expo >> 8;
+ exp[4] = expo;
break;
case SENSOR_HV7131R:
exp[0] |= (4 << 4);
exp[2] = 0x25;
- exp[3] = (sd->exposure >> 5) & 0xff;
- exp[4] = (sd->exposure << 3) & 0xff;
+ exp[3] = expo >> 5;
+ exp[4] = expo << 3;
exp[5] = 0;
break;
default:
- return 0;
+ return;
}
i2c_w(gspca_dev, exp);
- return 0;
}
-static int set_gain(struct gspca_dev *gspca_dev)
+static void set_gain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
+ int g;
+
+ g = sd->ctrls[GAIN].val;
switch (sd->sensor) {
case SENSOR_OV7660:
case SENSOR_OV7670:
@@ -1724,238 +1690,50 @@ static int set_gain(struct gspca_dev *gspca_dev)
case SENSOR_OV9655:
case SENSOR_OV9650:
gain[0] |= (2 << 4);
- gain[3] = ov_gain[sd->gain];
+ gain[3] = ov_gain[g];
break;
case SENSOR_MT9V011:
gain[0] |= (3 << 4);
gain[2] = 0x35;
- gain[3] = micron1_gain[sd->gain] >> 8;
- gain[4] = micron1_gain[sd->gain] & 0xff;
+ gain[3] = micron1_gain[g] >> 8;
+ gain[4] = micron1_gain[g];
break;
case SENSOR_MT9V112:
gain[0] |= (3 << 4);
gain[2] = 0x2f;
- gain[3] = micron1_gain[sd->gain] >> 8;
- gain[4] = micron1_gain[sd->gain] & 0xff;
+ gain[3] = micron1_gain[g] >> 8;
+ gain[4] = micron1_gain[g];
break;
case SENSOR_MT9M001:
gain[0] |= (3 << 4);
gain[2] = 0x2f;
- gain[3] = micron2_gain[sd->gain] >> 8;
- gain[4] = micron2_gain[sd->gain] & 0xff;
+ gain[3] = micron2_gain[g] >> 8;
+ gain[4] = micron2_gain[g];
break;
case SENSOR_HV7131R:
gain[0] |= (2 << 4);
gain[2] = 0x30;
- gain[3] = hv7131r_gain[sd->gain];
+ gain[3] = hv7131r_gain[g];
break;
default:
- return 0;
+ return;
}
i2c_w(gspca_dev, gain);
- return 0;
-}
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- return set_cmatrix(gspca_dev);
- return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->brightness;
- return 0;
-}
-
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->contrast = val;
- if (gspca_dev->streaming)
- return set_cmatrix(gspca_dev);
- return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->saturation = val;
- if (gspca_dev->streaming)
- return set_cmatrix(gspca_dev);
- return 0;
-}
-
-static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->saturation;
- return 0;
-}
-
-static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->hue = val;
- if (gspca_dev->streaming)
- return set_cmatrix(gspca_dev);
- return 0;
-}
-
-static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->hue;
- return 0;
-}
-
-static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gamma = val;
- if (gspca_dev->streaming)
- return set_gamma(gspca_dev);
- return 0;
-}
-
-static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->gamma;
- return 0;
-}
-
-static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->red = val;
- if (gspca_dev->streaming)
- return set_redblue(gspca_dev);
- return 0;
-}
-
-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->red;
- return 0;
}
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
+static void set_quality(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->blue = val;
- if (gspca_dev->streaming)
- return set_redblue(gspca_dev);
- return 0;
-}
-
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->blue;
- return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->hflip = val;
- if (gspca_dev->streaming)
- return set_hvflip(gspca_dev);
- return 0;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->hflip;
- return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->vflip = val;
- if (gspca_dev->streaming)
- return set_hvflip(gspca_dev);
- return 0;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->vflip;
- return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->exposure = val;
- if (gspca_dev->streaming)
- return set_exposure(gspca_dev);
- return 0;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->exposure;
- return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gain = val;
- if (gspca_dev->streaming)
- return set_gain(gspca_dev);
- return 0;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->gain;
- return 0;
-}
-
-static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- sd->auto_exposure = val;
- return 0;
-}
-
-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->auto_exposure;
- return 0;
+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+ reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */
+ reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
+ reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
+ reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
+ reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */
+ reg_w1(gspca_dev, 0x10e0, sd->fmt);
+ sd->fmt ^= 0x0c; /* invert QTAB use + write */
+ reg_w1(gspca_dev, 0x10e0, sd->fmt);
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1963,28 +1741,26 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
struct v4l2_dbg_register *reg)
{
struct sd *sd = (struct sd *) gspca_dev;
+
switch (reg->match.type) {
case V4L2_CHIP_MATCH_HOST:
if (reg->match.addr != 0)
return -EINVAL;
if (reg->reg < 0x1000 || reg->reg > 0x11ff)
return -EINVAL;
- if (reg_r(gspca_dev, reg->reg, 1) < 0)
- return -EINVAL;
+ reg_r(gspca_dev, reg->reg, 1);
reg->val = gspca_dev->usb_buf[0];
- return 0;
+ return gspca_dev->usb_err;
case V4L2_CHIP_MATCH_I2C_ADDR:
if (reg->match.addr != sd->i2c_addr)
return -EINVAL;
if (sd->sensor >= SENSOR_MT9V011 &&
sd->sensor <= SENSOR_MT9M112) {
- if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
- return -EINVAL;
+ i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
} else {
- if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
- return -EINVAL;
+ i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
}
- return 0;
+ return gspca_dev->usb_err;
}
return -EINVAL;
}
@@ -1993,27 +1769,25 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
struct v4l2_dbg_register *reg)
{
struct sd *sd = (struct sd *) gspca_dev;
+
switch (reg->match.type) {
case V4L2_CHIP_MATCH_HOST:
if (reg->match.addr != 0)
return -EINVAL;
if (reg->reg < 0x1000 || reg->reg > 0x11ff)
return -EINVAL;
- if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
- return -EINVAL;
- return 0;
+ reg_w1(gspca_dev, reg->reg, reg->val);
+ return gspca_dev->usb_err;
case V4L2_CHIP_MATCH_I2C_ADDR:
if (reg->match.addr != sd->i2c_addr)
return -EINVAL;
if (sd->sensor >= SENSOR_MT9V011 &&
sd->sensor <= SENSOR_MT9M112) {
- if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
- return -EINVAL;
+ i2c_w2(gspca_dev, reg->reg, reg->val);
} else {
- if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
- return -EINVAL;
+ i2c_w1(gspca_dev, reg->reg, reg->val);
}
- return 0;
+ return gspca_dev->usb_err;
}
return -EINVAL;
}
@@ -2048,10 +1822,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct cam *cam;
cam = &gspca_dev->cam;
+ cam->needs_full_bandwidth = 1;
- sd->sensor = (id->driver_info >> 8) & 0xff;
- sd->i2c_addr = id->driver_info & 0xff;
- sd->flags = (id->driver_info >> 16) & 0xff;
+ sd->sensor = id->driver_info >> 8;
+ sd->i2c_addr = id->driver_info;
+ sd->flags = id->driver_info >> 16;
switch (sd->sensor) {
case SENSOR_MT9M112:
@@ -2075,21 +1850,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->older_step = 0;
sd->exposure_step = 16;
- sd->brightness = BRIGHTNESS_DEFAULT;
- sd->contrast = CONTRAST_DEFAULT;
- sd->saturation = SATURATION_DEFAULT;
- sd->hue = HUE_DEFAULT;
- sd->gamma = GAMMA_DEFAULT;
- sd->red = RED_DEFAULT;
- sd->blue = BLUE_DEFAULT;
+ gspca_dev->cam.ctrls = sd->ctrls;
- sd->hflip = HFLIP_DEFAULT;
- sd->vflip = VFLIP_DEFAULT;
- sd->exposure = EXPOSURE_DEFAULT;
- sd->gain = GAIN_DEFAULT;
- sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
-
- sd->quality = 95;
+ INIT_WORK(&sd->work, qual_upd);
return 0;
}
@@ -2104,9 +1867,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
value = bridge_init[i][1];
- if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
+ reg_w(gspca_dev, bridge_init[i][0], &value, 1);
+ if (gspca_dev->usb_err < 0) {
pr_err("Device initialization failed\n");
- return -ENODEV;
+ return gspca_dev->usb_err;
}
}
@@ -2115,72 +1879,85 @@ static int sd_init(struct gspca_dev *gspca_dev)
else
reg_w1(gspca_dev, 0x1006, 0x20);
- if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
+ reg_w(gspca_dev, 0x10c0, i2c_init, 9);
+ if (gspca_dev->usb_err < 0) {
pr_err("Device initialization failed\n");
- return -ENODEV;
+ return gspca_dev->usb_err;
}
switch (sd->sensor) {
case SENSOR_OV9650:
- if (ov9650_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov9650_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV9650 sensor detected\n");
break;
case SENSOR_OV9655:
- if (ov9655_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov9655_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV9655 sensor detected\n");
break;
case SENSOR_SOI968:
- if (soi968_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ soi968_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("SOI968 sensor detected\n");
break;
case SENSOR_OV7660:
- if (ov7660_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov7660_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV7660 sensor detected\n");
break;
case SENSOR_OV7670:
- if (ov7670_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov7670_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV7670 sensor detected\n");
break;
case SENSOR_MT9VPRB:
- if (mt9v_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9v_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
+ pr_info("MT9VPRB sensor detected\n");
break;
case SENSOR_MT9M111:
- if (mt9m111_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9m111_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("MT9M111 sensor detected\n");
break;
case SENSOR_MT9M112:
- if (mt9m112_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9m112_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("MT9M112 sensor detected\n");
break;
case SENSOR_MT9M001:
- if (mt9m001_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9m001_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
break;
case SENSOR_HV7131R:
- if (hv7131r_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ hv7131r_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("HV7131R sensor detected\n");
break;
default:
- pr_info("Unsupported Sensor\n");
- return -ENODEV;
+ pr_err("Unsupported sensor\n");
+ gspca_dev->usb_err = -ENODEV;
}
- return 0;
+ return gspca_dev->usb_err;
}
static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 value;
+
switch (sd->sensor) {
case SENSOR_SOI968:
if (mode & MODE_SXGA) {
@@ -2233,6 +2010,43 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
}
}
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ struct usb_interface *intf;
+ u32 flags = gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv;
+
+ /*
+ * When using the SN9C20X_I420 fmt the sn9c20x needs more bandwidth
+ * than our regular bandwidth calculations reserve, so we force the
+ * use of a specific altsetting when using the SN9C20X_I420 fmt.
+ */
+ if (!(flags & (MODE_RAW | MODE_JPEG))) {
+ intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+
+ if (intf->num_altsetting != 9) {
+ pr_warn("sn9c20x camera with unknown number of alt "
+ "settings (%d), please report!\n",
+ intf->num_altsetting);
+ gspca_dev->alt = intf->num_altsetting;
+ return 0;
+ }
+
+ switch (gspca_dev->width) {
+ case 160: /* 160x120 */
+ gspca_dev->alt = 2;
+ break;
+ case 320: /* 320x240 */
+ gspca_dev->alt = 6;
+ break;
+ default: /* >= 640x480 */
+ gspca_dev->alt = 9;
+ break;
+ }
+ }
+
+ return 0;
+}
+
#define HW_WIN(mode, hstart, vstart) \
((const u8 []){hstart, 0, vstart, 0, \
(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
@@ -2253,14 +2067,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
jpeg_define(sd->jpeg_hdr, height, width,
0x21);
- jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
if (mode & MODE_RAW)
fmt = 0x2d;
else if (mode & MODE_JPEG)
- fmt = 0x2c;
+ fmt = 0x24;
else
fmt = 0x2f; /* YUV 420 */
+ sd->fmt = fmt;
switch (mode & SCALE_MASK) {
case SCALE_1280x1024:
@@ -2297,18 +2112,37 @@ static int sd_start(struct gspca_dev *gspca_dev)
set_hvflip(gspca_dev);
reg_w1(gspca_dev, 0x1007, 0x20);
+ reg_w1(gspca_dev, 0x1061, 0x03);
+
+ /* if JPEG, prepare the compression quality update */
+ if (mode & MODE_JPEG) {
+ sd->pktsz = sd->npkt = 0;
+ sd->nchg = 0;
+ sd->work_thread =
+ create_singlethread_workqueue(KBUILD_MODNAME);
+ }
- reg_r(gspca_dev, 0x1061, 1);
- reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
- return 0;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
reg_w1(gspca_dev, 0x1007, 0x00);
+ reg_w1(gspca_dev, 0x1061, 0x01);
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
- reg_r(gspca_dev, 0x1061, 1);
- reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
+ if (sd->work_thread != NULL) {
+ mutex_unlock(&gspca_dev->usb_lock);
+ destroy_workqueue(sd->work_thread);
+ mutex_lock(&gspca_dev->usb_lock);
+ sd->work_thread = NULL;
+ }
}
static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
@@ -2322,15 +2156,15 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
* and exposure steps
*/
if (avg_lum < MIN_AVG_LUM) {
- if (sd->exposure > 0x1770)
+ if (sd->ctrls[EXPOSURE].val > 0x1770)
return;
- new_exp = sd->exposure + sd->exposure_step;
+ new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step;
if (new_exp > 0x1770)
new_exp = 0x1770;
if (new_exp < 0x10)
new_exp = 0x10;
- sd->exposure = new_exp;
+ sd->ctrls[EXPOSURE].val = new_exp;
set_exposure(gspca_dev);
sd->older_step = sd->old_step;
@@ -2342,14 +2176,14 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
sd->exposure_step += 2;
}
if (avg_lum > MAX_AVG_LUM) {
- if (sd->exposure < 0x10)
+ if (sd->ctrls[EXPOSURE].val < 0x10)
return;
- new_exp = sd->exposure - sd->exposure_step;
+ new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step;
if (new_exp > 0x1700)
new_exp = 0x1770;
if (new_exp < 0x10)
new_exp = 0x10;
- sd->exposure = new_exp;
+ sd->ctrls[EXPOSURE].val = new_exp;
set_exposure(gspca_dev);
sd->older_step = sd->old_step;
sd->old_step = 0;
@@ -2366,14 +2200,14 @@ static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
struct sd *sd = (struct sd *) gspca_dev;
if (avg_lum < MIN_AVG_LUM) {
- if (sd->gain + 1 <= 28) {
- sd->gain++;
+ if (sd->ctrls[GAIN].val + 1 <= 28) {
+ sd->ctrls[GAIN].val++;
set_gain(gspca_dev);
}
}
if (avg_lum > MAX_AVG_LUM) {
- if (sd->gain > 0) {
- sd->gain--;
+ if (sd->ctrls[GAIN].val > 0) {
+ sd->ctrls[GAIN].val--;
set_gain(gspca_dev);
}
}
@@ -2384,7 +2218,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int avg_lum;
- if (!sd->auto_exposure)
+ if (!sd->ctrls[AUTOGAIN].val)
return;
avg_lum = atomic_read(&sd->avg_lum);
@@ -2394,33 +2228,92 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
do_autoexposure(gspca_dev, avg_lum);
}
+/* JPEG quality update */
+/* This function is executed from a work queue. */
+static void qual_upd(struct work_struct *work)
+{
+ struct sd *sd = container_of(work, struct sd, work);
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+ mutex_lock(&gspca_dev->usb_lock);
+ PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val);
+ set_quality(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+}
+
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet */
int len) /* interrupt packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret = -EINVAL;
+
if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
- input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
- input_sync(gspca_dev->input_dev);
- input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
- input_sync(gspca_dev->input_dev);
- ret = 0;
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+ input_sync(gspca_dev->input_dev);
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ return 0;
}
- return ret;
+ return -EINVAL;
}
#endif
+/* check the JPEG compression */
+static void transfer_check(struct gspca_dev *gspca_dev,
+ u8 *data)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int new_qual, r;
+
+ new_qual = 0;
+
+ /* if USB error, discard the frame and decrease the quality */
+ if (data[6] & 0x08) { /* USB FIFO full */
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ new_qual = -5;
+ } else {
+
+ /* else, compute the filling rate and a new JPEG quality */
+ r = (sd->pktsz * 100) /
+ (sd->npkt *
+ gspca_dev->urb[0]->iso_frame_desc[0].length);
+ if (r >= 85)
+ new_qual = -3;
+ else if (r < 75)
+ new_qual = 2;
+ }
+ if (new_qual != 0) {
+ sd->nchg += new_qual;
+ if (sd->nchg < -6 || sd->nchg >= 12) {
+ sd->nchg = 0;
+ new_qual += sd->ctrls[QUALITY].val;
+ if (new_qual < QUALITY_MIN)
+ new_qual = QUALITY_MIN;
+ else if (new_qual > QUALITY_MAX)
+ new_qual = QUALITY_MAX;
+ if (new_qual != sd->ctrls[QUALITY].val) {
+ sd->ctrls[QUALITY].val = new_qual;
+ queue_work(sd->work_thread, &sd->work);
+ }
+ }
+ } else {
+ sd->nchg = 0;
+ }
+ sd->pktsz = sd->npkt = 0;
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
- int avg_lum;
+ int avg_lum, is_jpeg;
static u8 frame_header[] =
{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
- if (len == 64 && memcmp(data, frame_header, 6) == 0) {
+
+ is_jpeg = (sd->fmt & 0x03) == 0;
+ if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
avg_lum = ((data[35] >> 2) & 3) |
(data[20] << 2) |
(data[19] << 10);
@@ -2447,12 +2340,18 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
(data[33] << 10);
avg_lum >>= 9;
atomic_set(&sd->avg_lum, avg_lum);
+
+ if (is_jpeg)
+ transfer_check(gspca_dev, data);
+
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
- return;
+ len -= 64;
+ if (len == 0)
+ return;
+ data += 64;
}
if (gspca_dev->last_packet_type == LAST_PACKET) {
- if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
- & MODE_JPEG) {
+ if (is_jpeg) {
gspca_frame_add(gspca_dev, FIRST_PACKET,
sd->jpeg_hdr, JPEG_HDR_SZ);
gspca_frame_add(gspca_dev, INTER_PACKET,
@@ -2462,19 +2361,26 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data, len);
}
} else {
+ /* if JPEG, count the packets and their size */
+ if (is_jpeg) {
+ sd->npkt++;
+ sd->pktsz += len;
+ }
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
}
/* sub-driver description */
static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
+ .isoc_init = sd_isoc_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
@@ -2543,7 +2449,7 @@ static int sd_probe(struct usb_interface *intf,
}
static struct usb_driver sd_driver = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index ddb392dc4f2d..6a1148d7fe92 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -1079,20 +1079,23 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
cam->npkt = 36; /* 36 packets per ISOC message */
- if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) {
- sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN;
- sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX;
- sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF;
- }
-
return 0;
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
const __u8 stop = 0x09; /* Disable stream turn of LED */
+ if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) {
+ sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN;
+ sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX;
+ sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF;
+ if (sd->ctrls[EXPOSURE].val > COARSE_EXPOSURE_MAX)
+ sd->ctrls[EXPOSURE].val = COARSE_EXPOSURE_DEF;
+ }
+
reg_w(gspca_dev, 0x01, &stop, 1);
return 0;
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index afa3186b8038..db8e5084df06 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -39,7 +39,9 @@ enum e_ctrl {
BLUE,
RED,
GAMMA,
+ EXPOSURE,
AUTOGAIN,
+ GAIN,
HFLIP,
VFLIP,
SHARPNESS,
@@ -131,7 +133,9 @@ static void setcontrast(struct gspca_dev *gspca_dev);
static void setcolors(struct gspca_dev *gspca_dev);
static void setredblue(struct gspca_dev *gspca_dev);
static void setgamma(struct gspca_dev *gspca_dev);
-static void setautogain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static void setgain(struct gspca_dev *gspca_dev);
static void sethvflip(struct gspca_dev *gspca_dev);
static void setsharpness(struct gspca_dev *gspca_dev);
static void setillum(struct gspca_dev *gspca_dev);
@@ -213,6 +217,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
},
.set_control = setgamma
},
+[EXPOSURE] = {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 500,
+ .maximum = 1500,
+ .step = 1,
+ .default_value = 1024
+ },
+ .set_control = setexposure
+ },
[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
@@ -223,7 +239,19 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
.step = 1,
.default_value = 1
},
- .set_control = setautogain
+ .set = sd_setautogain,
+ },
+[GAIN] = {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 4,
+ .maximum = 49,
+ .step = 1,
+ .default_value = 15
+ },
+ .set_control = setgain
},
[HFLIP] = {
{
@@ -290,60 +318,87 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
/* table of the disabled controls */
static const __u32 ctrl_dis[] = {
-[SENSOR_ADCM1700] = (1 << AUTOGAIN) |
+[SENSOR_ADCM1700] = (1 << EXPOSURE) |
+ (1 << AUTOGAIN) |
+ (1 << GAIN) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_GC0307] = (1 << HFLIP) |
+[SENSOR_GC0307] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_HV7131R] = (1 << HFLIP) |
+[SENSOR_HV7131R] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << FREQ),
-[SENSOR_MI0360] = (1 << HFLIP) |
+[SENSOR_MI0360] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_MI0360B] = (1 << HFLIP) |
+[SENSOR_MI0360B] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_MO4000] = (1 << HFLIP) |
+[SENSOR_MO4000] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_MT9V111] = (1 << HFLIP) |
+[SENSOR_MT9V111] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_OM6802] = (1 << HFLIP) |
+[SENSOR_OM6802] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_OV7630] = (1 << HFLIP),
+[SENSOR_OV7630] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP),
-[SENSOR_OV7648] = (1 << HFLIP),
+[SENSOR_OV7648] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP),
-[SENSOR_OV7660] = (1 << AUTOGAIN) |
+[SENSOR_OV7660] = (1 << EXPOSURE) |
+ (1 << AUTOGAIN) |
+ (1 << GAIN) |
(1 << HFLIP) |
(1 << VFLIP),
-[SENSOR_PO1030] = (1 << AUTOGAIN) |
+[SENSOR_PO1030] = (1 << EXPOSURE) |
+ (1 << AUTOGAIN) |
+ (1 << GAIN) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_PO2030N] = (1 << AUTOGAIN) |
- (1 << FREQ),
+[SENSOR_PO2030N] = (1 << FREQ),
-[SENSOR_SOI768] = (1 << AUTOGAIN) |
+[SENSOR_SOI768] = (1 << EXPOSURE) |
+ (1 << AUTOGAIN) |
+ (1 << GAIN) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_SP80708] = (1 << AUTOGAIN) |
+[SENSOR_SP80708] = (1 << EXPOSURE) |
+ (1 << AUTOGAIN) |
+ (1 << GAIN) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
@@ -1235,21 +1290,13 @@ static const u8 po2030n_sensor_param1[][8] = {
{DELAY, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */
{0xa1, 0x6e, 0x1b, 0xf4, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
- {0xd1, 0x6e, 0x16, 0x50, 0x40, 0x49, 0x40, 0x10},
+ {0xd1, 0x6e, 0x16, 0x40, 0x40, 0x40, 0x40, 0x10}, /* RGBG gains */
/*param2*/
{0xa1, 0x6e, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10},
- {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
- {0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10},
-/*after start*/
- {0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10},
- {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
- {0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10},
- {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
- {0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10},
{}
};
@@ -1779,10 +1826,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->ag_cnt = -1;
sd->quality = QUALITY_DEF;
- /* if USB 1.1, let some bandwidth for the audio device */
- if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH)
- gspca_dev->nbalt--;
-
INIT_WORK(&sd->work, qual_upd);
return 0;
@@ -1862,7 +1905,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
return gspca_dev->usb_err;
}
-static u32 setexposure(struct gspca_dev *gspca_dev,
+static u32 expo_adjust(struct gspca_dev *gspca_dev,
u32 expo)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1986,28 +2029,28 @@ static void setbrightness(struct gspca_dev *gspca_dev)
expo = 0x002dc6c0;
else if (expo < 0x02a0)
expo = 0x02a0;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
break;
case SENSOR_MI0360:
case SENSOR_MO4000:
expo = brightness << 4;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
break;
case SENSOR_MI0360B:
expo = brightness << 2;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
break;
case SENSOR_GC0307:
expo = brightness;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
return; /* don't set the Y offset */
case SENSOR_MT9V111:
expo = brightness << 2;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
return; /* don't set the Y offset */
case SENSOR_OM6802:
expo = brightness << 2;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
return; /* Y offset already set */
}
@@ -2063,6 +2106,16 @@ static void setredblue(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->sensor == SENSOR_PO2030N) {
+ u8 rg1b[] = /* red green1 blue (no g2) */
+ {0xc1, 0x6e, 0x16, 0x00, 0x40, 0x00, 0x00, 0x10};
+
+ /* 0x40 = normal value = gain x 1 */
+ rg1b[3] = sd->ctrls[RED].val * 2;
+ rg1b[5] = sd->ctrls[BLUE].val * 2;
+ i2c_w8(gspca_dev, rg1b);
+ return;
+ }
reg_w1(gspca_dev, 0x05, sd->ctrls[RED].val);
/* reg_w1(gspca_dev, 0x07, 32); */
reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val);
@@ -2106,6 +2159,23 @@ static void setgamma(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x20, gamma, sizeof gamma);
}
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PO2030N) {
+ u8 rexpo[] = /* 1a: expo H, 1b: expo M */
+ {0xa1, 0x6e, 0x1a, 0x00, 0x40, 0x00, 0x00, 0x10};
+
+ rexpo[3] = sd->ctrls[EXPOSURE].val >> 8;
+ i2c_w8(gspca_dev, rexpo);
+ msleep(6);
+ rexpo[2] = 0x1b;
+ rexpo[3] = sd->ctrls[EXPOSURE].val;
+ i2c_w8(gspca_dev, rexpo);
+ }
+}
+
static void setautogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2133,6 +2203,19 @@ static void setautogain(struct gspca_dev *gspca_dev)
sd->ag_cnt = -1;
}
+static void setgain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PO2030N) {
+ u8 rgain[] = /* 15: gain */
+ {0xa1, 0x6e, 0x15, 0x00, 0x40, 0x00, 0x00, 0x15};
+
+ rgain[3] = sd->ctrls[GAIN].val;
+ i2c_w8(gspca_dev, rgain);
+ }
+}
+
static void sethvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2397,7 +2480,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x17, reg17);
reg01 &= ~S_PWR_DN; /* sensor power on */
reg_w1(gspca_dev, 0x01, reg01);
- reg01 &= ~SYS_SEL_48M;
+ reg01 &= ~SCL_SEL_OD; /* remove open-drain mode */
reg_w1(gspca_dev, 0x01, reg01);
switch (sd->sensor) {
@@ -2617,6 +2700,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
setcontrast(gspca_dev);
setcolors(gspca_dev);
setautogain(gspca_dev);
+ if (!(gspca_dev->ctrl_inac & ((1 << EXPOSURE) | (1 << GAIN)))) {
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+ }
setfreq(gspca_dev);
sd->pktsz = sd->npkt = 0;
@@ -2713,6 +2800,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
}
}
+/* !! coarse_grained_expo_autogain is not used !! */
+#define exp_too_low_cnt bridge
+#define exp_too_high_cnt sensor
+
+#include "autogain_functions.h"
+
static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2730,6 +2823,13 @@ static void do_autogain(struct gspca_dev *gspca_dev)
delta = atomic_read(&sd->avg_lum);
PDEBUG(D_FRAM, "mean lum %d", delta);
+
+ if (sd->sensor == SENSOR_PO2030N) {
+ auto_gain_n_exposure(gspca_dev, delta, luma_mean, luma_delta,
+ 15, 1024);
+ return;
+ }
+
if (delta < luma_mean - luma_delta ||
delta > luma_mean + luma_delta) {
switch (sd->sensor) {
@@ -2738,7 +2838,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
expotimes += (luma_mean - delta) >> 6;
if (expotimes < 0)
expotimes = 0;
- sd->exposure = setexposure(gspca_dev,
+ sd->exposure = expo_adjust(gspca_dev,
(unsigned int) expotimes);
break;
case SENSOR_HV7131R:
@@ -2746,7 +2846,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
expotimes += (luma_mean - delta) >> 4;
if (expotimes < 0)
expotimes = 0;
- sd->exposure = setexposure(gspca_dev,
+ sd->exposure = expo_adjust(gspca_dev,
(unsigned int) (expotimes << 8));
break;
case SENSOR_OM6802:
@@ -2755,7 +2855,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
expotimes += (luma_mean - delta) >> 2;
if (expotimes < 0)
expotimes = 0;
- sd->exposure = setexposure(gspca_dev,
+ sd->exposure = expo_adjust(gspca_dev,
(unsigned int) expotimes);
setredblue(gspca_dev);
break;
@@ -2767,7 +2867,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
expotimes += (luma_mean - delta) >> 6;
if (expotimes < 0)
expotimes = 0;
- sd->exposure = setexposure(gspca_dev,
+ sd->exposure = expo_adjust(gspca_dev,
(unsigned int) expotimes);
setredblue(gspca_dev);
break;
@@ -2942,16 +3042,18 @@ marker_found:
}
}
-static int sd_get_jcomp(struct gspca_dev *gspca_dev,
- struct v4l2_jpegcompression *jcomp)
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- memset(jcomp, 0, sizeof *jcomp);
- jcomp->quality = sd->quality;
- jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
- | V4L2_JPEG_MARKER_DQT;
- return 0;
+ sd->ctrls[AUTOGAIN].val = val;
+ if (val)
+ gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
+ else
+ gspca_dev->ctrl_inac &= ~(1 << EXPOSURE) & ~(1 << GAIN);
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
+ return gspca_dev->usb_err;
}
static int sd_querymenu(struct gspca_dev *gspca_dev,
@@ -3006,7 +3108,6 @@ static const struct sd_desc sd_desc = {
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
- .get_jcomp = sd_get_jcomp,
.querymenu = sd_querymenu,
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index 259a0c73c664..4a5f209ce719 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -451,7 +451,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
cam = &gspca_dev->cam;
- gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
+ cam->needs_full_bandwidth = 1;
sd->chip_revision = id->driver_info;
if (sd->chip_revision == Rev012A) {
diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile
index 5b318faf9aa8..38bc41061d83 100644
--- a/drivers/media/video/gspca/stv06xx/Makefile
+++ b/drivers/media/video/gspca/stv06xx/Makefile
@@ -6,5 +6,5 @@ gspca_stv06xx-objs := stv06xx.o \
stv06xx_pb0100.o \
stv06xx_st6422.o
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 0ab425fbea9a..91d99b4cc57b 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -36,8 +36,8 @@ MODULE_AUTHOR("Erik Andrén");
MODULE_DESCRIPTION("STV06XX USB Camera Driver");
MODULE_LICENSE("GPL");
-static int dump_bridge;
-static int dump_sensor;
+static bool dump_bridge;
+static bool dump_sensor;
int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data)
{
@@ -304,7 +304,7 @@ static int stv06xx_isoc_init(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
/* Start isoc bandwidth "negotiation" at max isoc bandwidth */
- alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
alt->endpoint[0].desc.wMaxPacketSize =
cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]);
@@ -317,7 +317,7 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev)
struct usb_host_interface *alt;
struct sd *sd = (struct sd *) gspca_dev;
- alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode];
if (packet_size <= min_packet_size)
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index ea44deb66af4..9b9f85a8e60e 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -30,6 +30,7 @@
#define MODULE_NAME "t613"
+#include <linux/input.h>
#include <linux/slab.h>
#include "gspca.h"
@@ -57,6 +58,7 @@ struct sd {
u8 effect;
u8 sensor;
+ u8 button_pressed;
};
enum sensors {
SENSOR_OM6802,
@@ -1095,15 +1097,35 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
msleep(20);
reg_w(gspca_dev, 0x0309);
}
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ /* If the last button state is pressed, release it now! */
+ if (sd->button_pressed) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ sd->button_pressed = 0;
+ }
+#endif
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
int pkt_type;
if (data[0] == 0x5a) {
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ if (len > 20) {
+ u8 state = (data[20] & 0x80) ? 1 : 0;
+ if (sd->button_pressed != state) {
+ input_report_key(gspca_dev->input_dev,
+ KEY_CAMERA, state);
+ input_sync(gspca_dev->input_dev);
+ sd->button_pressed = state;
+ }
+ }
+#endif
/* Control Packet, after this came the header again,
* but extra bytes came in the packet before this,
* sometimes an EOF arrives, sometimes not... */
@@ -1410,6 +1432,9 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ .other_input = 1,
+#endif
};
/* -- module initialisation -- */
diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/video/gspca/topro.c
index b2695b1dc603..444d3c5b9079 100644
--- a/drivers/media/video/gspca/topro.c
+++ b/drivers/media/video/gspca/topro.c
@@ -3946,7 +3946,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev)
/* 640x480 * 30 fps does not work */
if (i == 6 /* if 30 fps */
&& gspca_dev->width == 640)
- i = 0x86; /* 15 fps */
+ i = 0x05; /* 15 fps */
} else {
for (i = 0; i < ARRAY_SIZE(rates_6810) - 1; i++) {
if (sd->framerate >= rates_6810[i])
diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c
index d12ea1518ace..911152e169d6 100644
--- a/drivers/media/video/gspca/vicam.c
+++ b/drivers/media/video/gspca/vicam.c
@@ -324,7 +324,8 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
dev->work_thread = NULL;
mutex_lock(&gspca_dev->usb_lock);
- vicam_set_camera_power(gspca_dev, 0);
+ if (gspca_dev->present)
+ vicam_set_camera_power(gspca_dev, 0);
}
/* Table of supported USB devices */
diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c
index fbb6ed25ec31..ecada178bceb 100644
--- a/drivers/media/video/gspca/xirlink_cit.c
+++ b/drivers/media/video/gspca/xirlink_cit.c
@@ -995,14 +995,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
case CIT_MODEL0:
cam->cam_mode = model0_mode;
cam->nmodes = ARRAY_SIZE(model0_mode);
- cam->reverse_alts = 1;
gspca_dev->ctrl_dis = ~((1 << SD_CONTRAST) | (1 << SD_HFLIP));
sd->sof_len = 4;
break;
case CIT_MODEL1:
cam->cam_mode = cif_yuv_mode;
cam->nmodes = ARRAY_SIZE(cif_yuv_mode);
- cam->reverse_alts = 1;
gspca_dev->ctrl_dis = (1 << SD_HUE) | (1 << SD_HFLIP);
sd->sof_len = 4;
break;
@@ -2791,7 +2789,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
}
/* Start isoc bandwidth "negotiation" at max isoc bandwidth */
- alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
return 0;
@@ -2814,7 +2812,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev)
break;
}
- alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
if (packet_size <= min_packet_size)
return -EIO;
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 0202fead6b97..7d9a4f1be9dc 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -1,7 +1,7 @@
/*
- * Z-Star/Vimicro zc301/zc302p/vc30x library
+ * Z-Star/Vimicro zc301/zc302p/vc30x driver
*
- * Copyright (C) 2009-2011 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2012 Jean-Francois Moine <http://moinejf.free.fr>
* Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr
*
* This program is free software; you can redistribute it and/or modify
@@ -21,8 +21,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#define MODULE_NAME "zc3xx"
-
#include <linux/input.h>
#include "gspca.h"
#include "jpeg.h"
@@ -34,7 +32,7 @@ MODULE_LICENSE("GPL");
static int force_sensor = -1;
-#define QUANT_VAL 1 /* quantization table */
+#define REG08_DEF 3 /* default JPEG compression (70%) */
#include "zc3xx-reg.h"
/* controls */
@@ -46,6 +44,7 @@ enum e_ctrl {
AUTOGAIN,
LIGHTFREQ,
SHARPNESS,
+ QUALITY,
NCTRLS /* number of controls */
};
@@ -57,10 +56,10 @@ struct sd {
struct gspca_ctrl ctrls[NCTRLS];
- u8 quality; /* image quality */
-#define QUALITY_MIN 50
-#define QUALITY_MAX 80
-#define QUALITY_DEF 70
+ struct work_struct work;
+ struct workqueue_struct *work_thread;
+
+ u8 reg08; /* webcam compression quality */
u8 bridge;
u8 sensor; /* Type of image sensor chip */
@@ -101,6 +100,7 @@ static void setexposure(struct gspca_dev *gspca_dev);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static void setlightfreq(struct gspca_dev *gspca_dev);
static void setsharpness(struct gspca_dev *gspca_dev);
+static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val);
static const struct ctrl sd_ctrls[NCTRLS] = {
[BRIGHTNESS] = {
@@ -188,6 +188,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
},
.set_control = setsharpness
},
+[QUALITY] = {
+ {
+ .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Compression Quality",
+ .minimum = 40,
+ .maximum = 70,
+ .step = 1,
+ .default_value = 70 /* updated in sd_init() */
+ },
+ .set = sd_setquality
+ },
};
static const struct v4l2_pix_format vga_mode[] = {
@@ -229,6 +241,9 @@ static const struct v4l2_pix_format sif_mode[] = {
.priv = 0},
};
+/* bridge reg08 -> JPEG quality conversion table */
+static u8 jpeg_qual[] = {40, 50, 60, 70, /*80*/};
+
/* usb exchanges */
struct usb_action {
u8 req;
@@ -3894,7 +3909,6 @@ static const struct usb_action pas106b_Initial[] = { /* 352x288 */
/* Gains */
{0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF},
{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP},
- {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN},
{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
/* Auto correction */
{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
@@ -5381,12 +5395,12 @@ static const struct usb_action tas5130c_NoFlikerScale[] = {
{}
};
-static const struct usb_action gc0303_InitialScale[] = {
+/* from usbvm305.inf 0ac8:305b 07/06/15 (3 - tas5130c) */
+static const struct usb_action gc0303_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
- {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc,
- * 0<->10 */
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */
{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */
{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */
@@ -5405,29 +5419,22 @@ static const struct usb_action gc0303_InitialScale[] = {
* 6<->8 */
{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */
{0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */
- {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */
- {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */
- {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */
- {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */
- {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
-/*?? {0xaa, 0x01, 0x0000}, */
{0xaa, 0x01, 0x0000},
{0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */
{0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */
+ {0xaa, 0x1b, 0x0000},
{0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */
{0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */
{0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */
{0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */
- {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */
- {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */
- {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */
- {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */
- {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */
- {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */
- {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */
- {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */
-/*?? {0xa0, 0x00, 0x0039},
- {0xa1, 0x01, 0x0037}, */
+ {0xaa, 0x0a, 0x0002},
+ {0xaa, 0x0b, 0x0000},
+ {0xaa, 0x0c, 0x0002},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x0e, 0x0002},
+ {0xaa, 0x0f, 0x0000},
+ {0xaa, 0x10, 0x0002},
+ {0xaa, 0x11, 0x0000},
{0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */
{0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa, (e6 -> e8) */
{0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */
@@ -5442,17 +5449,18 @@ static const struct usb_action gc0303_InitialScale[] = {
{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */
{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */
{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */
- {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */
+ {0xa0, 0x58, ZC3XX_R1A8_DIGITALGAIN},
{0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */
{0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */
+ {0xaa, 0x1b, 0x0000},
{}
};
-static const struct usb_action gc0303_Initial[] = {
+static const struct usb_action gc0303_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
- {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc, */
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */
{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */
{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */
@@ -5471,34 +5479,26 @@ static const struct usb_action gc0303_Initial[] = {
* 8<->6 */
{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */
{0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */
- {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */
- {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */
- {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */
- {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */
- {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
-/*?? {0xaa, 0x01, 0x0000}, */
{0xaa, 0x01, 0x0000},
{0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */
{0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */
+ {0xaa, 0x1b, 0x0000},
{0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */
{0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */
{0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */
{0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */
- {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */
- {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */
- {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */
- {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */
- {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */
- {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */
- {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */
- {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */
-/*?? {0xa0, 0x00, 0x0039},
- {0xa1, 0x01, 0x0037}, */
+ {0xaa, 0x0a, 0x0001},
+ {0xaa, 0x0b, 0x0000},
+ {0xaa, 0x0c, 0x0001},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x0e, 0x0001},
+ {0xaa, 0x0f, 0x0000},
+ {0xaa, 0x10, 0x0001},
+ {0xaa, 0x11, 0x0000},
{0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */
{0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */
{0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */
{0xaa, 0x19, 0x0088}, /* 00,19,88,aa, */
- {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */
{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */
{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */
{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */
@@ -5508,36 +5508,37 @@ static const struct usb_action gc0303_Initial[] = {
{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */
{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */
{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */
- {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */
+ {0xa0, 0x58, ZC3XX_R1A8_DIGITALGAIN},
{0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */
{0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */
+ {0xaa, 0x1b, 0x0000},
{}
};
-static const struct usb_action gc0303_50HZScale[] = {
+static const struct usb_action gc0303_50HZ[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
- {0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */
+ {0xaa, 0x84, 0x0063},
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
{0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */
{0xa0, 0xa8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
- {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */
+ {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */
{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */
{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */
{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */
- {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */
+ {0xa0, 0x48, ZC3XX_R1AA_DIGITALGAINSTEP},
{0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */
{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */
{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
- {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */
+ {0xa0, 0x7f, ZC3XX_R18D_YTARGET},
{}
};
-static const struct usb_action gc0303_50HZ[] = {
+static const struct usb_action gc0303_50HZScale[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0003}, /* 00,83,03,aa */
{0xaa, 0x84, 0x0054}, /* 00,84,54,aa */
@@ -5550,21 +5551,21 @@ static const struct usb_action gc0303_50HZ[] = {
{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */
{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */
{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */
- {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */
+ {0xa0, 0x48, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */
{0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */
{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */
{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
- {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */
+ {0xa0, 0x7f, ZC3XX_R18D_YTARGET},
{}
};
-static const struct usb_action gc0303_60HZScale[] = {
+static const struct usb_action gc0303_60HZ[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
- {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
- {0xaa, 0x84, 0x0062}, /* 00,84,62,aa */
+ {0xaa, 0x83, 0x0000},
+ {0xaa, 0x84, 0x003b},
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
{0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */
{0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */
@@ -5581,14 +5582,14 @@ static const struct usb_action gc0303_60HZScale[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
- {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */
+ {0xa0, 0x80, ZC3XX_R18D_YTARGET},
{}
};
-static const struct usb_action gc0303_60HZ[] = {
+static const struct usb_action gc0303_60HZScale[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
- {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */
- {0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */
+ {0xaa, 0x83, 0x0000},
+ {0xaa, 0x84, 0x0076},
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
{0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,1,0b,cc, */
{0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,2,10,cc, */
@@ -5605,18 +5606,18 @@ static const struct usb_action gc0303_60HZ[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,0,ff,cc, */
{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,d,58,cc, */
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
- {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,d,78,cc */
+ {0xa0, 0x80, ZC3XX_R18D_YTARGET},
{}
};
-static const struct usb_action gc0303_NoFlikerScale[] = {
+static const struct usb_action gc0303_NoFliker[] = {
{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
{0xaa, 0x84, 0x0020}, /* 00,84,20,aa */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,0,00,cc, */
- {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */
- {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */
+ {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */
@@ -5631,14 +5632,14 @@ static const struct usb_action gc0303_NoFlikerScale[] = {
{}
};
-static const struct usb_action gc0303_NoFliker[] = {
+static const struct usb_action gc0303_NoFlikerScale[] = {
{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
{0xaa, 0x84, 0x0020}, /* 00,84,20,aa */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
- {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc, */
- {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc, */
+ {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */
@@ -5653,7 +5654,7 @@ static const struct usb_action gc0303_NoFliker[] = {
{}
};
-static u8 reg_r_i(struct gspca_dev *gspca_dev,
+static u8 reg_r(struct gspca_dev *gspca_dev,
u16 index)
{
int ret;
@@ -5668,24 +5669,14 @@ static u8 reg_r_i(struct gspca_dev *gspca_dev,
index, gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- pr_err("reg_r_i err %d\n", ret);
+ pr_err("reg_r err %d\n", ret);
gspca_dev->usb_err = ret;
return 0;
}
return gspca_dev->usb_buf[0];
}
-static u8 reg_r(struct gspca_dev *gspca_dev,
- u16 index)
-{
- u8 ret;
-
- ret = reg_r_i(gspca_dev, index);
- PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret);
- return ret;
-}
-
-static void reg_w_i(struct gspca_dev *gspca_dev,
+static void reg_w(struct gspca_dev *gspca_dev,
u8 value,
u16 index)
{
@@ -5705,14 +5696,6 @@ static void reg_w_i(struct gspca_dev *gspca_dev,
}
}
-static void reg_w(struct gspca_dev *gspca_dev,
- u8 value,
- u16 index)
-{
- PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value);
- reg_w_i(gspca_dev, value, index);
-}
-
static u16 i2c_read(struct gspca_dev *gspca_dev,
u8 reg)
{
@@ -5721,16 +5704,14 @@ static u16 i2c_read(struct gspca_dev *gspca_dev,
if (gspca_dev->usb_err < 0)
return 0;
- reg_w_i(gspca_dev, reg, 0x0092);
- reg_w_i(gspca_dev, 0x02, 0x0090); /* <- read command */
+ reg_w(gspca_dev, reg, 0x0092);
+ reg_w(gspca_dev, 0x02, 0x0090); /* <- read command */
msleep(20);
- retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
+ retbyte = reg_r(gspca_dev, 0x0091); /* read status */
if (retbyte != 0x00)
pr_err("i2c_r status error %02x\n", retbyte);
- retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */
- retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */
- PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)",
- reg, retval, retbyte);
+ retval = reg_r(gspca_dev, 0x0095); /* read Lowbyte */
+ retval |= reg_r(gspca_dev, 0x0096) << 8; /* read Hightbyte */
return retval;
}
@@ -5743,16 +5724,14 @@ static u8 i2c_write(struct gspca_dev *gspca_dev,
if (gspca_dev->usb_err < 0)
return 0;
- reg_w_i(gspca_dev, reg, 0x92);
- reg_w_i(gspca_dev, valL, 0x93);
- reg_w_i(gspca_dev, valH, 0x94);
- reg_w_i(gspca_dev, 0x01, 0x90); /* <- write command */
+ reg_w(gspca_dev, reg, 0x92);
+ reg_w(gspca_dev, valL, 0x93);
+ reg_w(gspca_dev, valH, 0x94);
+ reg_w(gspca_dev, 0x01, 0x90); /* <- write command */
msleep(1);
- retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
+ retbyte = reg_r(gspca_dev, 0x0091); /* read status */
if (retbyte != 0x00)
pr_err("i2c_w status error %02x\n", retbyte);
- PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)",
- reg, valH, valL, retbyte);
return retbyte;
}
@@ -5809,7 +5788,7 @@ static void setmatrix(struct gspca_dev *gspca_dev)
static const u8 tas5130c_matrix[9] =
{0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68};
static const u8 gc0303_matrix[9] =
- {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
+ {0x6c, 0xea, 0xea, 0xea, 0x6c, 0xea, 0xea, 0xea, 0x6c};
static const u8 *matrix_tb[SENSOR_MAX] = {
[SENSOR_ADCM2700] = adcm2700_matrix,
[SENSOR_CS2102] = ov7620_matrix,
@@ -5919,6 +5898,8 @@ static void getexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->sensor != SENSOR_HV7131R)
+ return;
sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9)
| (i2c_read(gspca_dev, 0x26) << 1)
| (i2c_read(gspca_dev, 0x27) >> 7);
@@ -5929,6 +5910,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int val;
+ if (sd->sensor != SENSOR_HV7131R)
+ return;
val = sd->ctrls[EXPOSURE].val;
i2c_write(gspca_dev, 0x25, val >> 9, 0x00);
i2c_write(gspca_dev, 0x26, val >> 1, 0x00);
@@ -5938,32 +5921,20 @@ static void setexposure(struct gspca_dev *gspca_dev)
static void setquality(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 frxt;
+ s8 reg07;
+ reg07 = 0;
switch (sd->sensor) {
- case SENSOR_ADCM2700:
- case SENSOR_GC0305:
- case SENSOR_HV7131B:
- case SENSOR_HV7131R:
case SENSOR_OV7620:
+ reg07 = 0x30;
+ break;
+ case SENSOR_HV7131R:
case SENSOR_PAS202B:
- case SENSOR_PO2030:
- return;
+ return; /* done by work queue */
}
-/*fixme: is it really 0008 0007 0018 for all other sensors? */
- reg_w(gspca_dev, QUANT_VAL, 0x0008);
- frxt = 0x30;
- reg_w(gspca_dev, frxt, 0x0007);
-#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2
- frxt = 0xff;
-#elif QUANT_VAL == 3
- frxt = 0xf0;
-#elif QUANT_VAL == 4
- frxt = 0xe0;
-#else
- frxt = 0x20;
-#endif
- reg_w(gspca_dev, frxt, 0x0018);
+ reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
+ if (reg07 != 0)
+ reg_w(gspca_dev, reg07, 0x0007);
}
/* Matches the sensor's internal frame rate to the lighting frequency.
@@ -6097,6 +6068,115 @@ static void setautogain(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, autoval, 0x0180);
}
+/* update the transfer parameters */
+/* This function is executed from a work queue. */
+/* The exact use of the bridge registers 07 and 08 is not known.
+ * The following algorithm has been adapted from ms-win traces */
+static void transfer_update(struct work_struct *work)
+{
+ struct sd *sd = container_of(work, struct sd, work);
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+ int change, good;
+ u8 reg07, reg11;
+
+ /* synchronize with the main driver and initialize the registers */
+ mutex_lock(&gspca_dev->usb_lock);
+ reg07 = 0; /* max */
+ reg_w(gspca_dev, reg07, 0x0007);
+ reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
+ mutex_unlock(&gspca_dev->usb_lock);
+
+ good = 0;
+ for (;;) {
+ msleep(100);
+
+ /* get the transfer status */
+ /* the bit 0 of the bridge register 11 indicates overflow */
+ mutex_lock(&gspca_dev->usb_lock);
+ if (!gspca_dev->present || !gspca_dev->streaming)
+ goto err;
+ reg11 = reg_r(gspca_dev, 0x0011);
+ if (gspca_dev->usb_err < 0
+ || !gspca_dev->present || !gspca_dev->streaming)
+ goto err;
+
+ change = reg11 & 0x01;
+ if (change) { /* overflow */
+ switch (reg07) {
+ case 0: /* max */
+ reg07 = sd->sensor == SENSOR_HV7131R
+ ? 0x30 : 0x32;
+ if (sd->reg08 != 0) {
+ change = 3;
+ sd->reg08--;
+ }
+ break;
+ case 0x32:
+ reg07 -= 4;
+ break;
+ default:
+ reg07 -= 2;
+ break;
+ case 2:
+ change = 0; /* already min */
+ break;
+ }
+ good = 0;
+ } else { /* no overflow */
+ if (reg07 != 0) { /* if not max */
+ good++;
+ if (good >= 10) {
+ good = 0;
+ change = 1;
+ reg07 += 2;
+ switch (reg07) {
+ case 0x30:
+ if (sd->sensor == SENSOR_PAS202B)
+ reg07 += 2;
+ break;
+ case 0x32:
+ case 0x34:
+ reg07 = 0;
+ break;
+ }
+ }
+ } else { /* reg07 max */
+ if (sd->reg08 < sizeof jpeg_qual - 1) {
+ good++;
+ if (good > 10) {
+ sd->reg08++;
+ change = 2;
+ }
+ }
+ }
+ }
+ if (change) {
+ if (change & 1) {
+ reg_w(gspca_dev, reg07, 0x0007);
+ if (gspca_dev->usb_err < 0
+ || !gspca_dev->present
+ || !gspca_dev->streaming)
+ goto err;
+ }
+ if (change & 2) {
+ reg_w(gspca_dev, sd->reg08,
+ ZC3XX_R008_CLOCKSETTING);
+ if (gspca_dev->usb_err < 0
+ || !gspca_dev->present
+ || !gspca_dev->streaming)
+ goto err;
+ sd->ctrls[QUALITY].val = jpeg_qual[sd->reg08];
+ jpeg_set_qual(sd->jpeg_hdr,
+ jpeg_qual[sd->reg08]);
+ }
+ }
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
+ return;
+err:
+ mutex_unlock(&gspca_dev->usb_lock);
+}
+
static void send_unknown(struct gspca_dev *gspca_dev, int sensor)
{
reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */
@@ -6424,11 +6504,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor = id->driver_info;
gspca_dev->cam.ctrls = sd->ctrls;
- sd->quality = QUALITY_DEF;
+ sd->reg08 = REG08_DEF;
- /* if USB 1.1, let some bandwidth for the audio device */
- if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH)
- gspca_dev->nbalt--;
+ INIT_WORK(&sd->work, transfer_update);
return 0;
}
@@ -6481,6 +6559,27 @@ static int sd_init(struct gspca_dev *gspca_dev)
[SENSOR_PO2030] = 1,
[SENSOR_TAS5130C] = 1,
};
+ static const u8 reg08_tb[SENSOR_MAX] = {
+ [SENSOR_ADCM2700] = 1,
+ [SENSOR_CS2102] = 3,
+ [SENSOR_CS2102K] = 3,
+ [SENSOR_GC0303] = 2,
+ [SENSOR_GC0305] = 3,
+ [SENSOR_HDCS2020] = 1,
+ [SENSOR_HV7131B] = 3,
+ [SENSOR_HV7131R] = 3,
+ [SENSOR_ICM105A] = 3,
+ [SENSOR_MC501CB] = 3,
+ [SENSOR_MT9V111_1] = 3,
+ [SENSOR_MT9V111_3] = 3,
+ [SENSOR_OV7620] = 1,
+ [SENSOR_OV7630C] = 3,
+ [SENSOR_PAS106] = 3,
+ [SENSOR_PAS202B] = 3,
+ [SENSOR_PB0330] = 3,
+ [SENSOR_PO2030] = 2,
+ [SENSOR_TAS5130C] = 3,
+ };
sensor = zcxx_probeSensor(gspca_dev);
if (sensor >= 0)
@@ -6545,7 +6644,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
case 0x0e:
PDEBUG(D_PROBE, "Find Sensor PAS202B");
sd->sensor = SENSOR_PAS202B;
-/* sd->sharpness = 1; */
break;
case 0x0f:
PDEBUG(D_PROBE, "Find Sensor PAS106");
@@ -6633,13 +6731,21 @@ static int sd_init(struct gspca_dev *gspca_dev)
}
sd->ctrls[GAMMA].def = gamma[sd->sensor];
+ sd->reg08 = reg08_tb[sd->sensor];
+ sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08];
+ sd->ctrls[QUALITY].min = jpeg_qual[0];
+ sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1];
switch (sd->sensor) {
case SENSOR_HV7131R:
+ gspca_dev->ctrl_dis = (1 << QUALITY);
break;
case SENSOR_OV7630C:
gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
break;
+ case SENSOR_PAS202B:
+ gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE);
+ break;
default:
gspca_dev->ctrl_dis = (1 << EXPOSURE);
break;
@@ -6702,7 +6808,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* create the JPEG header */
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
- jpeg_set_qual(sd->jpeg_hdr, sd->quality);
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
switch (sd->sensor) {
@@ -6778,10 +6883,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_r(gspca_dev, 0x0180); /* from win */
reg_w(gspca_dev, 0x00, 0x0180);
break;
- default:
- setquality(gspca_dev);
- break;
}
+ setquality(gspca_dev);
+ jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08]);
setlightfreq(gspca_dev);
switch (sd->sensor) {
@@ -6793,8 +6897,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x40, 0x0117);
break;
case SENSOR_HV7131R:
- if (!sd->ctrls[AUTOGAIN].val)
- setexposure(gspca_dev);
+ setexposure(gspca_dev);
reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
break;
case SENSOR_GC0305:
@@ -6819,13 +6922,19 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
setautogain(gspca_dev);
- switch (sd->sensor) {
- case SENSOR_PO2030:
- msleep(50);
- reg_w(gspca_dev, 0x00, 0x0007); /* (from win traces) */
- reg_w(gspca_dev, 0x02, ZC3XX_R008_CLOCKSETTING);
- break;
+
+ /* start the transfer update thread if needed */
+ if (gspca_dev->usb_err >= 0) {
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ case SENSOR_PAS202B:
+ sd->work_thread =
+ create_singlethread_workqueue(KBUILD_MODNAME);
+ queue_work(sd->work_thread, &sd->work);
+ break;
+ }
}
+
return gspca_dev->usb_err;
}
@@ -6834,6 +6943,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->work_thread != NULL) {
+ mutex_unlock(&gspca_dev->usb_lock);
+ destroy_workqueue(sd->work_thread);
+ mutex_lock(&gspca_dev->usb_lock);
+ sd->work_thread = NULL;
+ }
if (!gspca_dev->present)
return;
send_unknown(gspca_dev, sd->sensor);
@@ -6910,19 +7025,33 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
+static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(jpeg_qual) - 1; i++) {
+ if (val <= jpeg_qual[i])
+ break;
+ }
+ if (i > 0
+ && i == sd->reg08
+ && val < jpeg_qual[sd->reg08])
+ i--;
+ sd->reg08 = i;
+ sd->ctrls[QUALITY].val = jpeg_qual[i];
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+ return gspca_dev->usb_err;
+}
+
static int sd_set_jcomp(struct gspca_dev *gspca_dev,
struct v4l2_jpegcompression *jcomp)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (jcomp->quality < QUALITY_MIN)
- sd->quality = QUALITY_MIN;
- else if (jcomp->quality > QUALITY_MAX)
- sd->quality = QUALITY_MAX;
- else
- sd->quality = jcomp->quality;
- if (gspca_dev->streaming)
- jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ sd_setquality(gspca_dev, jcomp->quality);
+ jcomp->quality = sd->ctrls[QUALITY].val;
return gspca_dev->usb_err;
}
@@ -6932,7 +7061,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
memset(jcomp, 0, sizeof *jcomp);
- jcomp->quality = sd->quality;
+ jcomp->quality = sd->ctrls[QUALITY].val;
jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
| V4L2_JPEG_MARKER_DQT;
return 0;
@@ -6955,7 +7084,7 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
#endif
static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
@@ -7040,7 +7169,7 @@ static int sd_probe(struct usb_interface *intf,
/* USB driver */
static struct usb_driver sd_driver = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 3f1a5b1beeba..6510110f53d0 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -49,7 +49,7 @@ module_param(default_audio_input, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / "
"1=RCA front / 2=S/PDIF");
-static int boost_audio;
+static bool boost_audio;
module_param(boost_audio, bool, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(boost_audio, "boost the audio signal");
@@ -154,10 +154,20 @@ static int device_authorization(struct hdpvr_device *dev)
}
#endif
+ dev->fw_ver = dev->usbc_buf[1];
+
v4l2_info(&dev->v4l2_dev, "firmware version 0x%x dated %s\n",
- dev->usbc_buf[1], &dev->usbc_buf[2]);
+ dev->fw_ver, &dev->usbc_buf[2]);
+
+ if (dev->fw_ver > 0x15) {
+ dev->options.brightness = 0x80;
+ dev->options.contrast = 0x40;
+ dev->options.hue = 0xf;
+ dev->options.saturation = 0x40;
+ dev->options.sharpness = 0x80;
+ }
- switch (dev->usbc_buf[1]) {
+ switch (dev->fw_ver) {
case HDPVR_FIRMWARE_VERSION:
dev->flags &= ~HDPVR_FLAG_AC3_CAP;
break;
@@ -169,7 +179,7 @@ static int device_authorization(struct hdpvr_device *dev)
default:
v4l2_info(&dev->v4l2_dev, "untested firmware, the driver might"
" not work.\n");
- if (dev->usbc_buf[1] >= HDPVR_FIRMWARE_VERSION_AC3)
+ if (dev->fw_ver >= HDPVR_FIRMWARE_VERSION_AC3)
dev->flags |= HDPVR_FLAG_AC3_CAP;
else
dev->flags &= ~HDPVR_FLAG_AC3_CAP;
@@ -270,6 +280,8 @@ static const struct hdpvr_options hdpvr_default_options = {
.bitrate_mode = HDPVR_CONSTANT,
.gop_mode = HDPVR_SIMPLE_IDR_GOP,
.audio_codec = V4L2_MPEG_AUDIO_ENCODING_AAC,
+ /* original picture controls for firmware version <= 0x15 */
+ /* updated in device_authorization() for newer firmware */
.brightness = 0x86,
.contrast = 0x80,
.hue = 0x80,
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index 087f7c08cb85..11ffe9cc1780 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -283,12 +283,13 @@ static int hdpvr_start_streaming(struct hdpvr_device *dev)
hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
+ dev->status = STATUS_STREAMING;
+
INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
queue_work(dev->workqueue, &dev->worker);
v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
"streaming started\n");
- dev->status = STATUS_STREAMING;
return 0;
}
@@ -722,21 +723,39 @@ static const s32 supported_v4l2_ctrls[] = {
};
static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc,
- int ac3)
+ int ac3, int fw_ver)
{
int err;
+ if (fw_ver > 0x15) {
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40);
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0x1e, 1, 0xf);
+ case V4L2_CID_SHARPNESS:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+ }
+ } else {
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+ case V4L2_CID_SHARPNESS:
+ return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+ }
+ }
+
switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_SHARPNESS:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
case V4L2_CID_MPEG_AUDIO_ENCODING:
return v4l2_ctrl_query_fill(
qc, V4L2_MPEG_AUDIO_ENCODING_AAC,
@@ -794,7 +813,8 @@ static int vidioc_queryctrl(struct file *file, void *private_data,
if (qc->id == supported_v4l2_ctrls[i])
return fill_queryctrl(&dev->options, qc,
- dev->flags & HDPVR_FLAG_AC3_CAP);
+ dev->flags & HDPVR_FLAG_AC3_CAP,
+ dev->fw_ver);
if (qc->id < supported_v4l2_ctrls[i])
break;
diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h
index d6439db1d18b..fea3c6926997 100644
--- a/drivers/media/video/hdpvr/hdpvr.h
+++ b/drivers/media/video/hdpvr/hdpvr.h
@@ -113,6 +113,7 @@ struct hdpvr_device {
/* usb control transfer buffer and lock */
struct mutex usbc_mutex;
u8 *usbc_buf;
+ u8 fw_ver;
};
static inline struct hdpvr_device *to_hdpvr_dev(struct v4l2_device *v4l2_dev)
diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c
index eec75bb57203..351e9bafe8fe 100644
--- a/drivers/media/video/imx074.c
+++ b/drivers/media/video/imx074.c
@@ -468,18 +468,7 @@ static struct i2c_driver imx074_i2c_driver = {
.id_table = imx074_id,
};
-static int __init imx074_mod_init(void)
-{
- return i2c_add_driver(&imx074_i2c_driver);
-}
-
-static void __exit imx074_mod_exit(void)
-{
- i2c_del_driver(&imx074_i2c_driver);
-}
-
-module_init(imx074_mod_init);
-module_exit(imx074_mod_exit);
+module_i2c_driver(imx074_i2c_driver);
MODULE_DESCRIPTION("Sony IMX074 Camera driver");
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
index e5ed4db32e7b..548236333cce 100644
--- a/drivers/media/video/indycam.c
+++ b/drivers/media/video/indycam.c
@@ -387,15 +387,4 @@ static struct i2c_driver indycam_driver = {
.id_table = indycam_id,
};
-static __init int init_indycam(void)
-{
- return i2c_add_driver(&indycam_driver);
-}
-
-static __exit void exit_indycam(void)
-{
- i2c_del_driver(&indycam_driver);
-}
-
-module_init(init_indycam);
-module_exit(exit_indycam);
+module_i2c_driver(indycam_driver);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 3ab875d036e1..04f192a0398a 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -244,7 +244,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
/* ----------------------------------------------------------------------- */
-static void ir_key_poll(struct IR_i2c *ir)
+static int ir_key_poll(struct IR_i2c *ir)
{
static u32 ir_key, ir_raw;
int rc;
@@ -253,20 +253,28 @@ static void ir_key_poll(struct IR_i2c *ir)
rc = ir->get_key(ir, &ir_key, &ir_raw);
if (rc < 0) {
dprintk(2,"error\n");
- return;
+ return rc;
}
if (rc) {
dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key);
rc_keydown(ir->rc, ir_key, 0);
}
+ return 0;
}
static void ir_work(struct work_struct *work)
{
+ int rc;
struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work);
- ir_key_poll(ir);
+ rc = ir_key_poll(ir);
+ if (rc == -ENODEV) {
+ rc_unregister_device(ir->rc);
+ ir->rc = NULL;
+ return;
+ }
+
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval));
}
@@ -446,7 +454,8 @@ static int ir_remove(struct i2c_client *client)
cancel_delayed_work_sync(&ir->work);
/* unregister device */
- rc_unregister_device(ir->rc);
+ if (ir->rc)
+ rc_unregister_device(ir->rc);
/* free memory */
kfree(ir);
@@ -462,7 +471,7 @@ static const struct i2c_device_id ir_kbd_id[] = {
{ }
};
-static struct i2c_driver driver = {
+static struct i2c_driver ir_kbd_driver = {
.driver = {
.name = "ir-kbd-i2c",
},
@@ -471,29 +480,10 @@ static struct i2c_driver driver = {
.id_table = ir_kbd_id,
};
+module_i2c_driver(ir_kbd_driver);
+
/* ----------------------------------------------------------------------- */
MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller");
MODULE_DESCRIPTION("input driver for i2c IR remote controls");
MODULE_LICENSE("GPL");
-
-static int __init ir_init(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit ir_fini(void)
-{
- i2c_del_driver(&driver);
-}
-
-module_init(ir_init);
-module_exit(ir_fini);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
index 71ab76a5ab26..77de8a45b46f 100644
--- a/drivers/media/video/ivtv/Makefile
+++ b/drivers/media/video/ivtv/Makefile
@@ -7,8 +7,8 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \
obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/video
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index b31ee1bceef8..c60424601cb9 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -21,6 +21,7 @@
#include "ivtv-driver.h"
#include "ivtv-ioctl.h"
#include "ivtv-controls.h"
+#include "ivtv-mailbox.h"
static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
{
@@ -99,3 +100,64 @@ struct cx2341x_handler_ops ivtv_cxhdl_ops = {
.s_video_encoding = ivtv_s_video_encoding,
.s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt,
};
+
+int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+
+ if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
+ *pts = (s64)((u64)itv->last_dec_timing[2] << 32) |
+ (u64)itv->last_dec_timing[1];
+ *frame = itv->last_dec_timing[0];
+ return 0;
+ }
+ *pts = 0;
+ *frame = 0;
+ if (atomic_read(&itv->decoding)) {
+ if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
+ IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
+ return -EIO;
+ }
+ memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
+ set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
+ *pts = (s64)((u64) data[2] << 32) | (u64) data[1];
+ *frame = data[0];
+ /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/
+ }
+ return 0;
+}
+
+static int ivtv_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl);
+
+ switch (ctrl->id) {
+ /* V4L2_CID_MPEG_VIDEO_DEC_PTS and V4L2_CID_MPEG_VIDEO_DEC_FRAME
+ control cluster */
+ case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+ return ivtv_g_pts_frame(itv, &itv->ctrl_pts->val64,
+ &itv->ctrl_frame->val64);
+ }
+ return 0;
+}
+
+static int ivtv_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl);
+
+ switch (ctrl->id) {
+ /* V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK and MULTILINGUAL_PLAYBACK
+ control cluster */
+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+ itv->audio_stereo_mode = itv->ctrl_audio_playback->val - 1;
+ itv->audio_bilingual_mode = itv->ctrl_audio_multilingual_playback->val - 1;
+ ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+ break;
+ }
+ return 0;
+}
+
+const struct v4l2_ctrl_ops ivtv_hdl_out_ops = {
+ .s_ctrl = ivtv_s_ctrl,
+ .g_volatile_ctrl = ivtv_g_volatile_ctrl,
+};
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h
index d12893dd0183..3999e6358312 100644
--- a/drivers/media/video/ivtv/ivtv-controls.h
+++ b/drivers/media/video/ivtv/ivtv-controls.h
@@ -22,5 +22,7 @@
#define IVTV_CONTROLS_H
extern struct cx2341x_handler_ops ivtv_cxhdl_ops;
+extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops;
+int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame);
#endif
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 41108a9a195e..679262ed13bc 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -55,7 +55,7 @@
#include "ivtv-routing.h"
#include "ivtv-controls.h"
#include "ivtv-gpio.h"
-
+#include <linux/dma-mapping.h>
#include <media/tveeprom.h>
#include <media/saa7115.h>
#include <media/v4l2-chip-ident.h>
@@ -99,7 +99,7 @@ static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
static unsigned int cardtype_c = 1;
static unsigned int tuner_c = 1;
-static unsigned int radio_c = 1;
+static int radio_c = 1;
static unsigned int i2c_clock_period_c = 1;
static char pal[] = "---";
static char secam[] = "--";
@@ -139,7 +139,7 @@ static int tunertype = -1;
static int newi2c = -1;
module_param_array(tuner, int, &tuner_c, 0644);
-module_param_array(radio, bool, &radio_c, 0644);
+module_param_array(radio, int, &radio_c, 0644);
module_param_array(cardtype, int, &cardtype_c, 0644);
module_param_string(pal, pal, sizeof(pal), 0644);
module_param_string(secam, secam, sizeof(secam), 0644);
@@ -731,9 +731,6 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
init_kthread_work(&itv->irq_work, ivtv_irq_work_handler);
- /* start counting open_id at 1 */
- itv->open_id = 1;
-
/* Initial settings */
itv->cxhdl.port = CX2341X_PORT_MEMORY;
itv->cxhdl.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
@@ -747,8 +744,6 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
itv->cur_dma_stream = -1;
itv->cur_pio_stream = -1;
- itv->audio_stereo_mode = AUDIO_STEREO;
- itv->audio_bilingual_mode = AUDIO_MONO_LEFT;
/* Ctrls */
itv->speed = 1000;
@@ -818,7 +813,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
IVTV_ERR("Can't enable device!\n");
return -EIO;
}
- if (pci_set_dma_mask(pdev, 0xffffffff)) {
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
IVTV_ERR("No suitable DMA available.\n");
return -EIO;
}
@@ -1203,6 +1198,32 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
itv->tuner_std = itv->std;
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ struct v4l2_ctrl_handler *hdl = itv->v4l2_dev.ctrl_handler;
+
+ itv->ctrl_pts = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
+ V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 1, 0);
+ itv->ctrl_frame = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
+ V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0x7fffffff, 1, 0);
+ /* Note: V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO is not supported,
+ mask that menu item. */
+ itv->ctrl_audio_playback =
+ v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops,
+ V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK,
+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO,
+ 1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO,
+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO);
+ itv->ctrl_audio_multilingual_playback =
+ v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops,
+ V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK,
+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO,
+ 1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO,
+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT);
+ if (hdl->error) {
+ retval = hdl->error;
+ goto free_i2c;
+ }
+ v4l2_ctrl_cluster(2, &itv->ctrl_pts);
+ v4l2_ctrl_cluster(2, &itv->ctrl_audio_playback);
ivtv_call_all(itv, video, s_std_output, itv->std);
/* Turn off the output signal. The mpeg decoder is not yet
active so without this you would get a green image until the
@@ -1239,6 +1260,7 @@ free_streams:
free_irq:
free_irq(itv->pdev->irq, (void *)itv);
free_i2c:
+ v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
exit_ivtv_i2c(itv);
free_io:
ivtv_iounmap(itv);
@@ -1378,7 +1400,7 @@ static void ivtv_remove(struct pci_dev *pdev)
else
type = IVTV_DEC_STREAM_TYPE_MPG;
ivtv_stop_v4l2_decode_stream(&itv->streams[type],
- VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+ V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0);
}
ivtv_halt_firmware(itv);
}
@@ -1394,6 +1416,8 @@ static void ivtv_remove(struct pci_dev *pdev)
ivtv_streams_cleanup(itv, 1);
ivtv_udma_free(itv);
+ v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
+
exit_ivtv_i2c(itv);
free_irq(itv->pdev->irq, (void *)itv);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 8f9cc17b518e..2e220028aad2 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -54,7 +54,6 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <linux/dvb/video.h>
@@ -331,8 +330,9 @@ struct ivtv_stream {
struct ivtv *itv; /* for ease of use */
const char *name; /* name of the stream */
int type; /* stream type */
+ u32 caps; /* V4L2 capabilities */
- u32 id;
+ struct v4l2_fh *fh; /* pointer to the streaming filehandle */
spinlock_t qlock; /* locks access to the queues */
unsigned long s_flags; /* status flags, see above */
int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */
@@ -379,7 +379,6 @@ struct ivtv_stream {
struct ivtv_open_id {
struct v4l2_fh fh;
- u32 open_id; /* unique ID for this file descriptor */
int type; /* stream type */
int yuv_frames; /* 1: started OUT_UDMA_YUV output mode */
struct ivtv *itv;
@@ -631,6 +630,16 @@ struct ivtv {
struct v4l2_device v4l2_dev;
struct cx2341x_handler cxhdl;
+ struct {
+ /* PTS/Frame count control cluster */
+ struct v4l2_ctrl *ctrl_pts;
+ struct v4l2_ctrl *ctrl_frame;
+ };
+ struct {
+ /* Audio Playback control cluster */
+ struct v4l2_ctrl *ctrl_audio_playback;
+ struct v4l2_ctrl *ctrl_audio_multilingual_playback;
+ };
struct v4l2_ctrl_handler hdl_gpio;
struct v4l2_subdev sd_gpio; /* GPIO sub-device */
u16 instance;
@@ -650,7 +659,6 @@ struct ivtv {
u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */
u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */
-
/* Locking */
spinlock_t lock; /* lock access to this struct */
struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 38f052257f46..c9663e885b9f 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -50,16 +50,16 @@ static int ivtv_claim_stream(struct ivtv_open_id *id, int type)
if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
/* someone already claimed this stream */
- if (s->id == id->open_id) {
+ if (s->fh == &id->fh) {
/* yes, this file descriptor did. So that's OK. */
return 0;
}
- if (s->id == -1 && (type == IVTV_DEC_STREAM_TYPE_VBI ||
+ if (s->fh == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI ||
type == IVTV_ENC_STREAM_TYPE_VBI)) {
/* VBI is handled already internally, now also assign
the file descriptor to this stream for external
reading of the stream. */
- s->id = id->open_id;
+ s->fh = &id->fh;
IVTV_DEBUG_INFO("Start Read VBI\n");
return 0;
}
@@ -67,7 +67,7 @@ static int ivtv_claim_stream(struct ivtv_open_id *id, int type)
IVTV_DEBUG_INFO("Stream %d is busy\n", type);
return -EBUSY;
}
- s->id = id->open_id;
+ s->fh = &id->fh;
if (type == IVTV_DEC_STREAM_TYPE_VBI) {
/* Enable reinsertion interrupt */
ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
@@ -104,7 +104,7 @@ void ivtv_release_stream(struct ivtv_stream *s)
struct ivtv *itv = s->itv;
struct ivtv_stream *s_vbi;
- s->id = -1;
+ s->fh = NULL;
if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) &&
test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
/* this stream is still in use internally */
@@ -136,7 +136,7 @@ void ivtv_release_stream(struct ivtv_stream *s)
/* was already cleared */
return;
}
- if (s_vbi->id != -1) {
+ if (s_vbi->fh) {
/* VBI stream still claimed by a file descriptor */
return;
}
@@ -268,11 +268,13 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
}
/* wait for more data to arrive */
+ mutex_unlock(&itv->serialize_lock);
prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
/* New buffers might have become available before we were added to the waitqueue */
if (!s->q_full.buffers)
schedule();
finish_wait(&s->waitq, &wait);
+ mutex_lock(&itv->serialize_lock);
if (signal_pending(current)) {
/* return if a signal was received */
IVTV_DEBUG_INFO("User stopped %s\n", s->name);
@@ -357,7 +359,7 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co
size_t tot_written = 0;
int single_frame = 0;
- if (atomic_read(&itv->capturing) == 0 && s->id == -1) {
+ if (atomic_read(&itv->capturing) == 0 && s->fh == NULL) {
/* shouldn't happen */
IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name);
return -EIO;
@@ -507,9 +509,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_
IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
- mutex_lock(&itv->serialize_lock);
rc = ivtv_start_capture(id);
- mutex_unlock(&itv->serialize_lock);
if (rc)
return rc;
return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
@@ -584,9 +584,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
/* Start decoder (returns 0 if already started) */
- mutex_lock(&itv->serialize_lock);
rc = ivtv_start_decoding(id, itv->speed);
- mutex_unlock(&itv->serialize_lock);
if (rc) {
IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
@@ -627,11 +625,13 @@ retry:
break;
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
+ mutex_unlock(&itv->serialize_lock);
prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
/* New buffers might have become free before we were added to the waitqueue */
if (!s->q_free.buffers)
schedule();
finish_wait(&s->waitq, &wait);
+ mutex_lock(&itv->serialize_lock);
if (signal_pending(current)) {
IVTV_DEBUG_INFO("User stopped %s\n", s->name);
return -EINTR;
@@ -686,12 +686,14 @@ retry:
if (mode == OUT_YUV)
ivtv_yuv_setup_stream_frame(itv);
+ mutex_unlock(&itv->serialize_lock);
prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
while (!(got_sig = signal_pending(current)) &&
test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
schedule();
}
finish_wait(&itv->dma_waitq, &wait);
+ mutex_lock(&itv->serialize_lock);
if (got_sig) {
IVTV_DEBUG_INFO("User interrupted %s\n", s->name);
return -EINTR;
@@ -756,9 +758,7 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
int rc;
- mutex_lock(&itv->serialize_lock);
rc = ivtv_start_capture(id);
- mutex_unlock(&itv->serialize_lock);
if (rc) {
IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
s->name, rc);
@@ -808,7 +808,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
id->type == IVTV_ENC_STREAM_TYPE_VBI) &&
test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
/* Also used internally, don't stop capturing */
- s->id = -1;
+ s->fh = NULL;
}
else {
ivtv_stop_v4l2_encode_stream(s, gop_end);
@@ -861,20 +861,9 @@ int ivtv_v4l2_close(struct file *filp)
IVTV_DEBUG_FILE("close %s\n", s->name);
- v4l2_fh_del(fh);
- v4l2_fh_exit(fh);
-
- /* Easy case first: this stream was never claimed by us */
- if (s->id != id->open_id) {
- kfree(id);
- return 0;
- }
-
- /* 'Unclaim' this stream */
-
/* Stop radio */
- mutex_lock(&itv->serialize_lock);
- if (id->type == IVTV_ENC_STREAM_TYPE_RAD) {
+ if (id->type == IVTV_ENC_STREAM_TYPE_RAD &&
+ v4l2_fh_is_singular_file(filp)) {
/* Closing radio device, return to TV mode */
ivtv_mute(itv);
/* Mark that the radio is no longer in use */
@@ -890,16 +879,28 @@ int ivtv_v4l2_close(struct file *filp)
if (atomic_read(&itv->capturing) > 0) {
/* Undo video mute */
ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
- v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) |
- (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
+ v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) |
+ (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
}
/* Done! Unmute and continue. */
ivtv_unmute(itv);
- ivtv_release_stream(s);
- } else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
+ }
+
+ v4l2_fh_del(fh);
+ v4l2_fh_exit(fh);
+
+ /* Easy case first: this stream was never claimed by us */
+ if (s->fh != &id->fh) {
+ kfree(id);
+ return 0;
+ }
+
+ /* 'Unclaim' this stream */
+
+ if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT];
- ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+ ivtv_stop_decoding(id, V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0);
/* If all output streams are closed, and if the user doesn't have
IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */
@@ -911,21 +912,25 @@ int ivtv_v4l2_close(struct file *filp)
ivtv_stop_capture(id, 0);
}
kfree(id);
- mutex_unlock(&itv->serialize_lock);
return 0;
}
-static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
+int ivtv_v4l2_open(struct file *filp)
{
-#ifdef CONFIG_VIDEO_ADV_DEBUG
struct video_device *vdev = video_devdata(filp);
-#endif
+ struct ivtv_stream *s = video_get_drvdata(vdev);
struct ivtv *itv = s->itv;
struct ivtv_open_id *item;
int res = 0;
IVTV_DEBUG_FILE("open %s\n", s->name);
+ if (ivtv_init_on_first_open(itv)) {
+ IVTV_ERR("Failed to initialize on device %s\n",
+ video_device_node_name(vdev));
+ return -ENXIO;
+ }
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
/* Unless ivtv_fw_debug is set, error out if firmware dead. */
if (ivtv_fw_debug) {
@@ -966,31 +971,19 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
return -ENOMEM;
}
v4l2_fh_init(&item->fh, s->vdev);
- if (res < 0) {
- v4l2_fh_exit(&item->fh);
- kfree(item);
- return res;
- }
item->itv = itv;
item->type = s->type;
- item->open_id = itv->open_id++;
filp->private_data = &item->fh;
+ v4l2_fh_add(&item->fh);
- if (item->type == IVTV_ENC_STREAM_TYPE_RAD) {
- /* Try to claim this stream */
- if (ivtv_claim_stream(item, item->type)) {
- /* No, it's already in use */
- v4l2_fh_exit(&item->fh);
- kfree(item);
- return -EBUSY;
- }
-
+ if (item->type == IVTV_ENC_STREAM_TYPE_RAD &&
+ v4l2_fh_is_singular_file(filp)) {
if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
if (atomic_read(&itv->capturing) > 0) {
/* switching to radio while capture is
in progress is not polite */
- ivtv_release_stream(s);
+ v4l2_fh_del(&item->fh);
v4l2_fh_exit(&item->fh);
kfree(item);
return -EBUSY;
@@ -1022,32 +1015,9 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
itv->yuv_info.stream_size = 0;
}
- v4l2_fh_add(&item->fh);
return 0;
}
-int ivtv_v4l2_open(struct file *filp)
-{
- int res;
- struct ivtv *itv = NULL;
- struct ivtv_stream *s = NULL;
- struct video_device *vdev = video_devdata(filp);
-
- s = video_get_drvdata(vdev);
- itv = s->itv;
-
- mutex_lock(&itv->serialize_lock);
- if (ivtv_init_on_first_open(itv)) {
- IVTV_ERR("Failed to initialize on device %s\n",
- video_device_node_name(vdev));
- mutex_unlock(&itv->serialize_lock);
- return -ENXIO;
- }
- res = ivtv_serialized_open(s, filp);
- mutex_unlock(&itv->serialize_lock);
- return res;
-}
-
void ivtv_mute(struct ivtv *itv)
{
if (atomic_read(&itv->capturing))
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
index 9332920ca4ff..7b9ec1cfeb80 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.h
+++ b/drivers/media/video/ivtv/ivtv-i2c.h
@@ -25,7 +25,7 @@ struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv);
int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw);
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
int init_ivtv_i2c(struct ivtv *itv);
void exit_ivtv_i2c(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index ecafa697326e..989e556913ed 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -179,6 +179,7 @@ int ivtv_set_speed(struct ivtv *itv, int speed)
ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0);
/* Wait for any DMA to finish */
+ mutex_unlock(&itv->serialize_lock);
prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
while (test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
got_sig = signal_pending(current);
@@ -188,6 +189,7 @@ int ivtv_set_speed(struct ivtv *itv, int speed)
schedule();
}
finish_wait(&itv->dma_waitq, &wait);
+ mutex_lock(&itv->serialize_lock);
if (got_sig)
return -EINTR;
@@ -244,34 +246,40 @@ static int ivtv_validate_speed(int cur_speed, int new_speed)
}
static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
- struct video_command *vc, int try)
+ struct v4l2_decoder_cmd *dc, int try)
{
struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
- switch (vc->cmd) {
- case VIDEO_CMD_PLAY: {
- vc->flags = 0;
- vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed);
- if (vc->play.speed < 0)
- vc->play.format = VIDEO_PLAY_FMT_GOP;
+ switch (dc->cmd) {
+ case V4L2_DEC_CMD_START: {
+ dc->flags &= V4L2_DEC_CMD_START_MUTE_AUDIO;
+ dc->start.speed = ivtv_validate_speed(itv->speed, dc->start.speed);
+ if (dc->start.speed < 0)
+ dc->start.format = V4L2_DEC_START_FMT_GOP;
+ else
+ dc->start.format = V4L2_DEC_START_FMT_NONE;
+ if (dc->start.speed != 500 && dc->start.speed != 1500)
+ dc->flags = dc->start.speed == 1000 ? 0 :
+ V4L2_DEC_CMD_START_MUTE_AUDIO;
if (try) break;
+ itv->speed_mute_audio = dc->flags & V4L2_DEC_CMD_START_MUTE_AUDIO;
if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)
return -EBUSY;
if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
/* forces ivtv_set_speed to be called */
itv->speed = 0;
}
- return ivtv_start_decoding(id, vc->play.speed);
+ return ivtv_start_decoding(id, dc->start.speed);
}
- case VIDEO_CMD_STOP:
- vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK;
- if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY)
- vc->stop.pts = 0;
+ case V4L2_DEC_CMD_STOP:
+ dc->flags &= V4L2_DEC_CMD_STOP_IMMEDIATELY | V4L2_DEC_CMD_STOP_TO_BLACK;
+ if (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY)
+ dc->stop.pts = 0;
if (try) break;
if (atomic_read(&itv->decoding) == 0)
return 0;
@@ -279,22 +287,22 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
return -EBUSY;
itv->output_mode = OUT_NONE;
- return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts);
+ return ivtv_stop_v4l2_decode_stream(s, dc->flags, dc->stop.pts);
- case VIDEO_CMD_FREEZE:
- vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK;
+ case V4L2_DEC_CMD_PAUSE:
+ dc->flags &= V4L2_DEC_CMD_PAUSE_TO_BLACK;
if (try) break;
if (itv->output_mode != OUT_MPG)
return -EBUSY;
if (atomic_read(&itv->decoding) > 0) {
ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,
- (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0);
+ (dc->flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? 1 : 0);
set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
}
break;
- case VIDEO_CMD_CONTINUE:
- vc->flags = 0;
+ case V4L2_DEC_CMD_RESUME:
+ dc->flags = 0;
if (try) break;
if (itv->output_mode != OUT_MPG)
return -EBUSY;
@@ -752,12 +760,15 @@ static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register
static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap)
{
- struct ivtv *itv = fh2id(fh)->itv;
+ struct ivtv_open_id *id = fh2id(file->private_data);
+ struct ivtv *itv = id->itv;
+ struct ivtv_stream *s = &itv->streams[id->type];
strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
- vcap->capabilities = itv->v4l2_cap; /* capabilities */
+ vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
+ vcap->device_caps = s->caps;
return 0;
}
@@ -1107,6 +1118,7 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std)
* happens within the first 100 lines of the top field.
* Make 4 attempts to sync to the decoder before giving up.
*/
+ mutex_unlock(&itv->serialize_lock);
for (f = 0; f < 4; f++) {
prepare_to_wait(&itv->vsync_waitq, &wait,
TASK_UNINTERRUPTIBLE);
@@ -1115,6 +1127,7 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std)
schedule_timeout(msecs_to_jiffies(25));
}
finish_wait(&itv->vsync_waitq, &wait);
+ mutex_lock(&itv->serialize_lock);
if (f == 4)
IVTV_WARN("Mode change failed to sync to decoder\n");
@@ -1472,8 +1485,6 @@ static int ivtv_log_status(struct file *file, void *fh)
struct v4l2_audio audin;
int i;
- IVTV_INFO("================= START STATUS CARD #%d =================\n",
- itv->instance);
IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
if (itv->hw_flags & IVTV_HW_TVEEPROM) {
struct tveeprom tv;
@@ -1497,13 +1508,6 @@ static int ivtv_log_status(struct file *file, void *fh)
"YUV Frames",
"Passthrough",
};
- static const char * const audio_modes[5] = {
- "Stereo",
- "Left",
- "Right",
- "Mono",
- "Swapped"
- };
static const char * const alpha_mode[4] = {
"None",
"Global",
@@ -1532,9 +1536,6 @@ static int ivtv_log_status(struct file *file, void *fh)
ivtv_get_output(itv, itv->active_output, &vidout);
ivtv_get_audio_output(itv, 0, &audout);
IVTV_INFO("Video Output: %s\n", vidout.name);
- IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
- audio_modes[itv->audio_stereo_mode],
- audio_modes[itv->audio_bilingual_mode]);
if (mode < 0 || mode > OUT_PASSTHROUGH)
mode = OUT_NONE;
IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
@@ -1562,12 +1563,27 @@ static int ivtv_log_status(struct file *file, void *fh)
IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n",
(long long)itv->mpg_data_received,
(long long)itv->vbi_data_inserted);
- IVTV_INFO("================== END STATUS CARD #%d ==================\n",
- itv->instance);
-
return 0;
}
+static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
+{
+ struct ivtv_open_id *id = fh2id(file->private_data);
+ struct ivtv *itv = id->itv;
+
+ IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd);
+ return ivtv_video_command(itv, id, dec, false);
+}
+
+static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
+{
+ struct ivtv_open_id *id = fh2id(file->private_data);
+ struct ivtv *itv = id->itv;
+
+ IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd);
+ return ivtv_video_command(itv, id, dec, true);
+}
+
static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
{
struct ivtv_open_id *id = fh2id(filp->private_data);
@@ -1601,9 +1617,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
return ivtv_yuv_prep_frame(itv, args);
}
+ case IVTV_IOC_PASSTHROUGH_MODE:
+ IVTV_DEBUG_IOCTL("IVTV_IOC_PASSTHROUGH_MODE\n");
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return -EINVAL;
+ return ivtv_passthrough_mode(itv, *(int *)arg != 0);
+
case VIDEO_GET_PTS: {
- u32 data[CX2341X_MBOX_MAX_DATA];
- u64 *pts = arg;
+ s64 *pts = arg;
+ s64 frame;
IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n");
if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
@@ -1612,29 +1634,12 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
}
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
-
- if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
- *pts = (u64) ((u64)itv->last_dec_timing[2] << 32) |
- (u64)itv->last_dec_timing[1];
- break;
- }
- *pts = 0;
- if (atomic_read(&itv->decoding)) {
- if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
- IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
- return -EIO;
- }
- memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
- set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
- *pts = (u64) ((u64) data[2] << 32) | (u64) data[1];
- /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/
- }
- break;
+ return ivtv_g_pts_frame(itv, pts, &frame);
}
case VIDEO_GET_FRAME_COUNT: {
- u32 data[CX2341X_MBOX_MAX_DATA];
- u64 *frame = arg;
+ s64 *frame = arg;
+ s64 pts;
IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n");
if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
@@ -1643,71 +1648,58 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
}
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
-
- if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
- *frame = itv->last_dec_timing[0];
- break;
- }
- *frame = 0;
- if (atomic_read(&itv->decoding)) {
- if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
- IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
- return -EIO;
- }
- memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
- set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
- *frame = data[0];
- }
- break;
+ return ivtv_g_pts_frame(itv, &pts, frame);
}
case VIDEO_PLAY: {
- struct video_command vc;
+ struct v4l2_decoder_cmd dc;
IVTV_DEBUG_IOCTL("VIDEO_PLAY\n");
- memset(&vc, 0, sizeof(vc));
- vc.cmd = VIDEO_CMD_PLAY;
- return ivtv_video_command(itv, id, &vc, 0);
+ memset(&dc, 0, sizeof(dc));
+ dc.cmd = V4L2_DEC_CMD_START;
+ return ivtv_video_command(itv, id, &dc, 0);
}
case VIDEO_STOP: {
- struct video_command vc;
+ struct v4l2_decoder_cmd dc;
IVTV_DEBUG_IOCTL("VIDEO_STOP\n");
- memset(&vc, 0, sizeof(vc));
- vc.cmd = VIDEO_CMD_STOP;
- vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY;
- return ivtv_video_command(itv, id, &vc, 0);
+ memset(&dc, 0, sizeof(dc));
+ dc.cmd = V4L2_DEC_CMD_STOP;
+ dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY;
+ return ivtv_video_command(itv, id, &dc, 0);
}
case VIDEO_FREEZE: {
- struct video_command vc;
+ struct v4l2_decoder_cmd dc;
IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n");
- memset(&vc, 0, sizeof(vc));
- vc.cmd = VIDEO_CMD_FREEZE;
- return ivtv_video_command(itv, id, &vc, 0);
+ memset(&dc, 0, sizeof(dc));
+ dc.cmd = V4L2_DEC_CMD_PAUSE;
+ return ivtv_video_command(itv, id, &dc, 0);
}
case VIDEO_CONTINUE: {
- struct video_command vc;
+ struct v4l2_decoder_cmd dc;
IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n");
- memset(&vc, 0, sizeof(vc));
- vc.cmd = VIDEO_CMD_CONTINUE;
- return ivtv_video_command(itv, id, &vc, 0);
+ memset(&dc, 0, sizeof(dc));
+ dc.cmd = V4L2_DEC_CMD_RESUME;
+ return ivtv_video_command(itv, id, &dc, 0);
}
case VIDEO_COMMAND:
case VIDEO_TRY_COMMAND: {
- struct video_command *vc = arg;
+ /* Note: struct v4l2_decoder_cmd has the same layout as
+ struct video_command */
+ struct v4l2_decoder_cmd *dc = arg;
int try = (cmd == VIDEO_TRY_COMMAND);
if (try)
- IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd);
+ IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", dc->cmd);
else
- IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd);
- return ivtv_video_command(itv, id, vc, try);
+ IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", dc->cmd);
+ return ivtv_video_command(itv, id, dc, try);
}
case VIDEO_GET_EVENT: {
@@ -1771,17 +1763,13 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n");
if (iarg > AUDIO_STEREO_SWAPPED)
return -EINVAL;
- itv->audio_stereo_mode = iarg;
- ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
- return 0;
+ return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg + 1);
case AUDIO_BILINGUAL_CHANNEL_SELECT:
IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n");
if (iarg > AUDIO_STEREO_SWAPPED)
return -EINVAL;
- itv->audio_bilingual_mode = iarg;
- ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
- return 0;
+ return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg + 1);
default:
return -EINVAL;
@@ -1796,6 +1784,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
if (!valid_prio) {
switch (cmd) {
+ case IVTV_IOC_PASSTHROUGH_MODE:
case VIDEO_PLAY:
case VIDEO_STOP:
case VIDEO_FREEZE:
@@ -1821,6 +1810,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
}
case IVTV_IOC_DMA_FRAME:
+ case IVTV_IOC_PASSTHROUGH_MODE:
case VIDEO_GET_PTS:
case VIDEO_GET_FRAME_COUNT:
case VIDEO_GET_EVENT:
@@ -1842,8 +1832,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
return 0;
}
-static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp,
- unsigned int cmd, unsigned long arg)
+long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct video_device *vfd = video_devdata(filp);
long ret;
@@ -1855,21 +1844,6 @@ static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp,
return ret;
}
-long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- struct ivtv_open_id *id = fh2id(filp->private_data);
- struct ivtv *itv = id->itv;
- long res;
-
- /* DQEVENT can block, so this should not run with the serialize lock */
- if (cmd == VIDIOC_DQEVENT)
- return ivtv_serialized_ioctl(itv, filp, cmd, arg);
- mutex_lock(&itv->serialize_lock);
- res = ivtv_serialized_ioctl(itv, filp, cmd, arg);
- mutex_unlock(&itv->serialize_lock);
- return res;
-}
-
static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
.vidioc_querycap = ivtv_querycap,
.vidioc_s_audio = ivtv_s_audio,
@@ -1901,6 +1875,8 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
.vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap,
.vidioc_encoder_cmd = ivtv_encoder_cmd,
.vidioc_try_encoder_cmd = ivtv_try_encoder_cmd,
+ .vidioc_decoder_cmd = ivtv_decoder_cmd,
+ .vidioc_try_decoder_cmd = ivtv_try_decoder_cmd,
.vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out,
.vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap,
.vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap,
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index 9c29e964d400..1b3b9578bf47 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -288,13 +288,13 @@ static void dma_post(struct ivtv_stream *s)
ivtv_process_vbi_data(itv, buf, 0, s->type);
s->q_dma.bytesused += buf->bytesused;
}
- if (s->id == -1) {
+ if (s->fh == NULL) {
ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
return;
}
}
ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused);
- if (s->id != -1)
+ if (s->fh)
wake_up(&s->waitq);
}
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index e7794dc1330e..7ea5ca7f012b 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -78,60 +78,73 @@ static struct {
int num_offset;
int dma, pio;
enum v4l2_buf_type buf_type;
+ u32 v4l2_caps;
const struct v4l2_file_operations *fops;
} ivtv_stream_info[] = {
{ /* IVTV_ENC_STREAM_TYPE_MPG */
"encoder MPG",
VFL_TYPE_GRABBER, 0,
PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
&ivtv_v4l2_enc_fops
},
{ /* IVTV_ENC_STREAM_TYPE_YUV */
"encoder YUV",
VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET,
PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
&ivtv_v4l2_enc_fops
},
{ /* IVTV_ENC_STREAM_TYPE_VBI */
"encoder VBI",
VFL_TYPE_VBI, 0,
PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE,
+ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_TUNER |
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
&ivtv_v4l2_enc_fops
},
{ /* IVTV_ENC_STREAM_TYPE_PCM */
"encoder PCM",
VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET,
PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE,
+ V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
&ivtv_v4l2_enc_fops
},
{ /* IVTV_ENC_STREAM_TYPE_RAD */
"encoder radio",
VFL_TYPE_RADIO, 0,
PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE,
+ V4L2_CAP_RADIO | V4L2_CAP_TUNER,
&ivtv_v4l2_enc_fops
},
{ /* IVTV_DEC_STREAM_TYPE_MPG */
"decoder MPG",
VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
&ivtv_v4l2_dec_fops
},
{ /* IVTV_DEC_STREAM_TYPE_VBI */
"decoder VBI",
VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET,
PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE,
+ V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE,
&ivtv_v4l2_enc_fops
},
{ /* IVTV_DEC_STREAM_TYPE_VOUT */
"decoder VOUT",
VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET,
PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT,
+ V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
&ivtv_v4l2_dec_fops
},
{ /* IVTV_DEC_STREAM_TYPE_YUV */
"decoder YUV",
VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET,
PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
&ivtv_v4l2_dec_fops
}
};
@@ -149,6 +162,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
s->itv = itv;
s->type = type;
s->name = ivtv_stream_info[type].name;
+ s->caps = ivtv_stream_info[type].v4l2_caps;
if (ivtv_stream_info[type].pio)
s->dma = PCI_DMA_NONE;
@@ -159,7 +173,6 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size;
spin_lock_init(&s->qlock);
init_waitqueue_head(&s->waitq);
- s->id = -1;
s->sg_handle = IVTV_DMA_UNMAPPED;
ivtv_queue_init(&s->q_free);
ivtv_queue_init(&s->q_full);
@@ -210,10 +223,11 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
s->vdev->num = num;
s->vdev->v4l2_dev = &itv->v4l2_dev;
- s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler;
s->vdev->fops = ivtv_stream_info[type].fops;
+ s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler;
s->vdev->release = video_device_release;
s->vdev->tvnorms = V4L2_STD_ALL;
+ s->vdev->lock = &itv->serialize_lock;
set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags);
ivtv_set_funcs(s->vdev);
return 0;
@@ -891,7 +905,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags);
/* Stop Decoder */
- if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) {
+ if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) {
u32 tmp = 0;
/* Wait until the decoder is no longer running */
@@ -911,7 +925,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
break;
}
}
- ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0);
+ ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & V4L2_DEC_CMD_STOP_TO_BLACK, 0, 0);
/* turn off notification of dual/stereo mode change */
ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c
index 69cc8166b20b..7338cb2d0a38 100644
--- a/drivers/media/video/ivtv/ivtv-udma.c
+++ b/drivers/media/video/ivtv/ivtv-udma.c
@@ -57,9 +57,9 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info
if (dma->bouncemap[map_offset] == NULL)
return -1;
local_irq_save(flags);
- src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset;
+ src = kmap_atomic(dma->map[map_offset]) + offset;
memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len);
- kunmap_atomic(src, KM_BOUNCE_READ);
+ kunmap_atomic(src);
local_irq_restore(flags);
sg_set_page(&dma->SGlist[map_offset], dma->bouncemap[map_offset], len, offset);
}
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index dcbab6ad4c26..2ad65eb29832 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -1149,23 +1149,37 @@ int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
{
struct yuv_playback_info *yi = &itv->yuv_info;
struct ivtv_dma_frame dma_args;
+ int res;
ivtv_yuv_setup_stream_frame(itv);
/* We only need to supply source addresses for this */
dma_args.y_source = src;
dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
- return ivtv_yuv_udma_frame(itv, &dma_args);
+ /* Wait for frame DMA. Note that serialize_lock is locked,
+ so to allow other processes to access the driver while
+ we are waiting unlock first and later lock again. */
+ mutex_unlock(&itv->serialize_lock);
+ res = ivtv_yuv_udma_frame(itv, &dma_args);
+ mutex_lock(&itv->serialize_lock);
+ return res;
}
/* IVTV_IOC_DMA_FRAME ioctl handler */
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
{
-/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
+ int res;
+/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
ivtv_yuv_next_free(itv);
ivtv_yuv_setup_frame(itv, args);
- return ivtv_yuv_udma_frame(itv, args);
+ /* Wait for frame DMA. Note that serialize_lock is locked,
+ so to allow other processes to access the driver while
+ we are waiting unlock first and later lock again. */
+ mutex_unlock(&itv->serialize_lock);
+ res = ivtv_yuv_udma_frame(itv, args);
+ mutex_lock(&itv->serialize_lock);
+ return res;
}
void ivtv_yuv_close(struct ivtv *itv)
@@ -1174,7 +1188,9 @@ void ivtv_yuv_close(struct ivtv *itv)
int h_filter, v_filter_1, v_filter_2;
IVTV_DEBUG_YUV("ivtv_yuv_close\n");
+ mutex_unlock(&itv->serialize_lock);
ivtv_waitq(&itv->vsync_waitq);
+ mutex_lock(&itv->serialize_lock);
yi->running = 0;
atomic_set(&yi->next_dma_frame, -1);
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 6b7c9c823330..e5e7fa9e737b 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -58,7 +58,7 @@
/* card parameters */
static int ivtvfb_card_id = -1;
static int ivtvfb_debug = 0;
-static int osd_laced;
+static bool osd_laced;
static int osd_depth;
static int osd_upper;
static int osd_left;
@@ -1293,7 +1293,6 @@ static int __init ivtvfb_init(void)
drv = driver_find("ivtv", &pci_bus_type);
err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
- put_driver(drv);
if (!registered) {
printk(KERN_ERR "ivtvfb: no cards found\n");
return -ENODEV;
@@ -1310,7 +1309,6 @@ static void ivtvfb_cleanup(void)
drv = driver_find("ivtv", &pci_bus_type);
err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
- put_driver(drv);
}
module_init(ivtvfb_init);
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index afa91182b448..ee7ca2dcca2f 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -721,15 +721,4 @@ static struct i2c_driver ks0127_driver = {
.id_table = ks0127_id,
};
-static __init int init_ks0127(void)
-{
- return i2c_add_driver(&ks0127_driver);
-}
-
-static __exit void exit_ks0127(void)
-{
- i2c_del_driver(&ks0127_driver);
-}
-
-module_init(init_ks0127);
-module_exit(exit_ks0127);
+module_i2c_driver(ks0127_driver);
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
index 303ffa7df4ac..0991576f4c82 100644
--- a/drivers/media/video/m52790.c
+++ b/drivers/media/video/m52790.c
@@ -213,15 +213,4 @@ static struct i2c_driver m52790_driver = {
.id_table = m52790_id,
};
-static __init int init_m52790(void)
-{
- return i2c_add_driver(&m52790_driver);
-}
-
-static __exit void exit_m52790(void)
-{
- i2c_del_driver(&m52790_driver);
-}
-
-module_init(init_m52790);
-module_exit(exit_m52790);
+module_i2c_driver(m52790_driver);
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h
index 82c8817bd32d..4b021e1ee5f2 100644
--- a/drivers/media/video/m5mols/m5mols.h
+++ b/drivers/media/video/m5mols/m5mols.h
@@ -163,7 +163,6 @@ struct m5mols_version {
* @ffmt: current fmt according to resolution type
* @res_type: current resolution type
* @irq_waitq: waitqueue for the capture
- * @work_irq: workqueue for the IRQ
* @flags: state variable for the interrupt handler
* @handle: control handler
* @autoexposure: Auto Exposure control
@@ -175,14 +174,12 @@ struct m5mols_version {
* @ver: information of the version
* @cap: the capture mode attributes
* @power: current sensor's power status
- * @ctrl_sync: true means all controls of the sensor are initialized
- * @int_capture: true means the capture interrupt is issued once
+ * @isp_ready: 1 when the ISP controller has completed booting
+ * @ctrl_sync: 1 when the control handler state is restored in H/W
* @lock_ae: true means the Auto Exposure is locked
* @lock_awb: true means the Aut WhiteBalance is locked
* @resolution: register value for current resolution
- * @interrupt: register value for current interrupt status
* @mode: register value for current operation mode
- * @mode_save: register value for current operation mode for saving
* @set_power: optional power callback to the board code
*/
struct m5mols_info {
@@ -191,16 +188,16 @@ struct m5mols_info {
struct media_pad pad;
struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
int res_type;
+
wait_queue_head_t irq_waitq;
- struct work_struct work_irq;
- unsigned long flags;
+ atomic_t irq_done;
struct v4l2_ctrl_handler handle;
+
/* Autoexposure/exposure control cluster */
- struct {
- struct v4l2_ctrl *autoexposure;
- struct v4l2_ctrl *exposure;
- };
+ struct v4l2_ctrl *autoexposure;
+ struct v4l2_ctrl *exposure;
+
struct v4l2_ctrl *autowb;
struct v4l2_ctrl *colorfx;
struct v4l2_ctrl *saturation;
@@ -208,21 +205,19 @@ struct m5mols_info {
struct m5mols_version ver;
struct m5mols_capture cap;
- bool power;
- bool ctrl_sync;
+
+ unsigned int isp_ready:1;
+ unsigned int power:1;
+ unsigned int ctrl_sync:1;
+
bool lock_ae;
bool lock_awb;
u8 resolution;
- u8 interrupt;
u8 mode;
- u8 mode_save;
+
int (*set_power)(struct device *dev, int on);
};
-#define ST_CAPT_IRQ 0
-
-#define is_powered(__info) (__info->power)
-#define is_ctrl_synced(__info) (__info->ctrl_sync)
#define is_available_af(__info) (__info->ver.af)
#define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code)
#define is_manufacturer(__info, __manufacturer) \
@@ -257,7 +252,15 @@ int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val);
int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val);
int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
-int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value);
+
+int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
+ int timeout);
+
+/* Mask value for busy waiting until M-5MOLS I2C interface is initialized */
+#define M5MOLS_I2C_RDY_WAIT_FL (1 << 16)
+/* ISP state transition timeout, in ms */
+#define M5MOLS_MODE_CHANGE_TIMEOUT 200
+#define M5MOLS_BUSY_WAIT_DEF_TIMEOUT 250
/*
* Mode operation of the M-5MOLS
@@ -282,7 +285,8 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value);
int m5mols_mode(struct m5mols_info *info, u8 mode);
int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
-int m5mols_sync_controls(struct m5mols_info *info);
+int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
+int m5mols_restore_controls(struct m5mols_info *info);
int m5mols_start_capture(struct m5mols_info *info);
int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
int m5mols_lock_3a(struct m5mols_info *info, bool lock);
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c
index 3248ac805711..ba25e8e2ba4c 100644
--- a/drivers/media/video/m5mols/m5mols_capture.c
+++ b/drivers/media/video/m5mols/m5mols_capture.c
@@ -1,3 +1,4 @@
+
/*
* The Capture code for Fujitsu M-5MOLS ISP
*
@@ -25,26 +26,11 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/m5mols.h>
+#include <media/s5p_fimc.h>
#include "m5mols.h"
#include "m5mols_reg.h"
-static int m5mols_capture_error_handler(struct m5mols_info *info,
- int timeout)
-{
- int ret;
-
- /* Disable all interrupts and clear relevant interrupt staus bits */
- ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE,
- info->interrupt & ~(REG_INT_CAPTURE));
- if (ret)
- return ret;
-
- if (timeout == 0)
- return -ETIMEDOUT;
-
- return 0;
-}
/**
* m5mols_read_rational - I2C read of a rational number
*
@@ -121,69 +107,54 @@ int m5mols_start_capture(struct m5mols_info *info)
{
struct v4l2_subdev *sd = &info->sd;
u8 resolution = info->resolution;
- int timeout;
int ret;
/*
- * Preparing capture. Setting control & interrupt before entering
- * capture mode
- *
- * 1) change to MONITOR mode for operating control & interrupt
- * 2) set controls (considering v4l2_control value & lock 3A)
- * 3) set interrupt
- * 4) change to CAPTURE mode
+ * Synchronize the controls, set the capture frame resolution and color
+ * format. The frame capture is initiated during switching from Monitor
+ * to Capture mode.
*/
ret = m5mols_mode(info, REG_MONITOR);
if (!ret)
- ret = m5mols_sync_controls(info);
+ ret = m5mols_restore_controls(info);
if (!ret)
- ret = m5mols_lock_3a(info, true);
+ ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
+ if (!ret)
+ ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution);
if (!ret)
- ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
+ ret = m5mols_lock_3a(info, true);
if (!ret)
ret = m5mols_mode(info, REG_CAPTURE);
- if (!ret) {
- /* Wait for capture interrupt, after changing capture mode */
- timeout = wait_event_interruptible_timeout(info->irq_waitq,
- test_bit(ST_CAPT_IRQ, &info->flags),
- msecs_to_jiffies(2000));
- if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags))
- ret = m5mols_capture_error_handler(info, timeout);
- }
+ if (!ret)
+ /* Wait until a frame is captured to ISP internal memory */
+ ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
if (!ret)
ret = m5mols_lock_3a(info, false);
if (ret)
return ret;
+
/*
- * Starting capture. Setting capture frame count and resolution and
- * the format(available format: JPEG, Bayer RAW, YUV).
- *
- * 1) select single or multi(enable to 25), format, size
- * 2) set interrupt
- * 3) start capture(for main image, now)
- * 4) get information
- * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device)
+ * Initiate the captured data transfer to a MIPI-CSI receiver.
*/
ret = m5mols_write(sd, CAPC_SEL_FRAME, 1);
if (!ret)
- ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
- if (!ret)
- ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution);
- if (!ret)
- ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
- if (!ret)
ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
if (!ret) {
+ bool captured = false;
+ unsigned int size;
+
/* Wait for the capture completion interrupt */
- timeout = wait_event_interruptible_timeout(info->irq_waitq,
- test_bit(ST_CAPT_IRQ, &info->flags),
- msecs_to_jiffies(2000));
- if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) {
+ ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
+ if (!ret) {
+ captured = true;
ret = m5mols_capture_info(info);
- if (!ret)
- v4l2_subdev_notify(sd, 0, &info->cap.total);
}
+ size = captured ? info->cap.main : 0;
+ v4l2_dbg(1, m5mols_debug, sd, "%s: size: %d, thumb.: %d B\n",
+ __func__, size, info->cap.thumb);
+
+ v4l2_subdev_notify(sd, S5P_FIMC_TX_END_NOTIFY, &size);
}
- return m5mols_capture_error_handler(info, timeout);
+ return ret;
}
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c
index e0f09e531800..d718aee01c77 100644
--- a/drivers/media/video/m5mols/m5mols_core.c
+++ b/drivers/media/video/m5mols/m5mols_core.c
@@ -135,10 +135,13 @@ static u32 m5mols_swap_byte(u8 *data, u8 length)
* @reg: combination of size, category and command for the I2C packet
* @size: desired size of I2C packet
* @val: read value
+ *
+ * Returns 0 on success, or else negative errno.
*/
static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct m5mols_info *info = to_m5mols(sd);
u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
u8 category = I2C_CATEGORY(reg);
u8 cmd = I2C_COMMAND(reg);
@@ -168,15 +171,17 @@ static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
usleep_range(200, 200);
ret = i2c_transfer(client->adapter, msg, 2);
- if (ret < 0) {
- v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
- size, category, cmd, ret);
- return ret;
+
+ if (ret == 2) {
+ *val = m5mols_swap_byte(&rbuf[1], size);
+ return 0;
}
- *val = m5mols_swap_byte(&rbuf[1], size);
+ if (info->isp_ready)
+ v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
+ size, category, cmd, ret);
- return 0;
+ return ret < 0 ? ret : -EIO;
}
int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val)
@@ -229,10 +234,13 @@ int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val)
* m5mols_write - I2C command write function
* @reg: combination of size, category and command for the I2C packet
* @val: value to write
+ *
+ * Returns 0 on success, or else negative errno.
*/
int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct m5mols_info *info = to_m5mols(sd);
u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4];
u8 category = I2C_CATEGORY(reg);
u8 cmd = I2C_COMMAND(reg);
@@ -263,28 +271,45 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
usleep_range(200, 200);
ret = i2c_transfer(client->adapter, msg, 1);
- if (ret < 0) {
- v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n",
- size, category, cmd, ret);
- return ret;
- }
+ if (ret == 1)
+ return 0;
- return 0;
+ if (info->isp_ready)
+ v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n",
+ category, cmd, ret);
+
+ return ret < 0 ? ret : -EIO;
}
-int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask)
+/**
+ * m5mols_busy_wait - Busy waiting with I2C register polling
+ * @reg: the I2C_REG() address of an 8-bit status register to check
+ * @value: expected status register value
+ * @mask: bit mask for the read status register value
+ * @timeout: timeout in miliseconds, or -1 for default timeout
+ *
+ * The @reg register value is ORed with @mask before comparing with @value.
+ *
+ * Return: 0 if the requested condition became true within less than
+ * @timeout ms, or else negative errno.
+ */
+int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
+ int timeout)
{
- u8 busy;
- int i;
- int ret;
+ int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout;
+ unsigned long end = jiffies + msecs_to_jiffies(ms);
+ u8 status;
- for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) {
- ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy);
- if (ret < 0)
+ do {
+ int ret = m5mols_read_u8(sd, reg, &status);
+
+ if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL))
return ret;
- if ((busy & mask) == mask)
+ if (!ret && (status & mask & 0xff) == (value & 0xff))
return 0;
- }
+ usleep_range(100, 250);
+ } while (ms > 0 && time_is_after_jiffies(end));
+
return -EBUSY;
}
@@ -307,6 +332,20 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
return ret;
}
+int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+
+ int ret = wait_event_interruptible_timeout(info->irq_waitq,
+ atomic_add_unless(&info->irq_done, -1, 0),
+ msecs_to_jiffies(timeout));
+ if (ret <= 0)
+ return ret ? ret : -ETIMEDOUT;
+
+ return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask,
+ M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1);
+}
+
/**
* m5mols_reg_mode - Write the mode and check busy status
*
@@ -316,8 +355,10 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode)
{
int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
-
- return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode);
+ if (ret < 0)
+ return ret;
+ return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff,
+ M5MOLS_MODE_CHANGE_TIMEOUT);
}
/**
@@ -338,13 +379,13 @@ int m5mols_mode(struct m5mols_info *info, u8 mode)
return ret;
ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, &reg);
- if ((!ret && reg == mode) || ret)
+ if (ret || reg == mode)
return ret;
switch (reg) {
case REG_PARAMETER:
ret = m5mols_reg_mode(sd, REG_MONITOR);
- if (!ret && mode == REG_MONITOR)
+ if (mode == REG_MONITOR)
break;
if (!ret)
ret = m5mols_reg_mode(sd, REG_CAPTURE);
@@ -361,7 +402,7 @@ int m5mols_mode(struct m5mols_info *info, u8 mode)
case REG_CAPTURE:
ret = m5mols_reg_mode(sd, REG_MONITOR);
- if (!ret && mode == REG_MONITOR)
+ if (mode == REG_MONITOR)
break;
if (!ret)
ret = m5mols_reg_mode(sd, REG_PARAMETER);
@@ -570,26 +611,25 @@ static struct v4l2_subdev_pad_ops m5mols_pad_ops = {
};
/**
- * m5mols_sync_controls - Apply default scene mode and the current controls
+ * m5mols_restore_controls - Apply current control values to the registers
*
- * This is used only streaming for syncing between v4l2_ctrl framework and
- * m5mols's controls. First, do the scenemode to the sensor, then call
- * v4l2_ctrl_handler_setup. It can be same between some commands and
- * the scenemode's in the default v4l2_ctrls. But, such commands of control
- * should be prior to the scenemode's one.
+ * m5mols_do_scenemode() handles all parameters for which there is yet no
+ * individual control. It should be replaced at some point by setting each
+ * control individually, in required register set up order.
*/
-int m5mols_sync_controls(struct m5mols_info *info)
+int m5mols_restore_controls(struct m5mols_info *info)
{
- int ret = -EINVAL;
+ int ret;
- if (!is_ctrl_synced(info)) {
- ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
- if (ret)
- return ret;
+ if (info->ctrl_sync)
+ return 0;
- v4l2_ctrl_handler_setup(&info->handle);
- info->ctrl_sync = true;
- }
+ ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
+ if (ret)
+ return ret;
+
+ ret = v4l2_ctrl_handler_setup(&info->handle);
+ info->ctrl_sync = !ret;
return ret;
}
@@ -613,7 +653,7 @@ static int m5mols_start_monitor(struct m5mols_info *info)
if (!ret)
ret = m5mols_mode(info, REG_MONITOR);
if (!ret)
- ret = m5mols_sync_controls(info);
+ ret = m5mols_restore_controls(info);
return ret;
}
@@ -645,17 +685,25 @@ static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_sd(ctrl);
struct m5mols_info *info = to_m5mols(sd);
+ int ispstate = info->mode;
int ret;
- info->mode_save = info->mode;
+ /*
+ * If needed, defer restoring the controls until
+ * the device is fully initialized.
+ */
+ if (!info->isp_ready) {
+ info->ctrl_sync = 0;
+ return 0;
+ }
ret = m5mols_mode(info, REG_PARAMETER);
- if (!ret)
- ret = m5mols_set_ctrl(ctrl);
- if (!ret)
- ret = m5mols_mode(info, info->mode_save);
-
- return ret;
+ if (ret < 0)
+ return ret;
+ ret = m5mols_set_ctrl(ctrl);
+ if (ret < 0)
+ return ret;
+ return m5mols_mode(info, ispstate);
}
static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
@@ -669,10 +717,10 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
const struct m5mols_platform_data *pdata = info->pdata;
int ret;
- if (enable) {
- if (is_powered(info))
- return 0;
+ if (info->power == enable)
+ return 0;
+ if (enable) {
if (info->set_power) {
ret = info->set_power(&client->dev, 1);
if (ret)
@@ -686,15 +734,11 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
}
gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity);
- usleep_range(1000, 1000);
- info->power = true;
+ info->power = 1;
return ret;
}
- if (!is_powered(info))
- return 0;
-
ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
if (ret)
return ret;
@@ -703,8 +747,9 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
info->set_power(&client->dev, 0);
gpio_set_value(pdata->gpio_reset, pdata->reset_polarity);
- usleep_range(1000, 1000);
- info->power = false;
+
+ info->isp_ready = 0;
+ info->power = 0;
return ret;
}
@@ -717,21 +762,29 @@ int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
}
/**
- * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core.
+ * m5mols_fw_start - M-5MOLS internal ARM controller initialization
*
- * Booting internal ARM core makes the M-5MOLS is ready for getting commands
- * with I2C. It's the first thing to be done after it powered up. It must wait
- * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting.
+ * Execute the M-5MOLS internal ARM controller initialization sequence.
+ * This function should be called after the supply voltage has been
+ * applied and before any requests to the device are made.
*/
-static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
+static int m5mols_fw_start(struct v4l2_subdev *sd)
{
+ struct m5mols_info *info = to_m5mols(sd);
int ret;
- ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
+ atomic_set(&info->irq_done, 0);
+ /* Wait until I2C slave is initialized in Flash Writer mode */
+ ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE,
+ M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1);
+ if (!ret)
+ ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
+ if (!ret)
+ ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000);
if (ret < 0)
return ret;
- msleep(520);
+ info->isp_ready = 1;
ret = m5mols_get_version(sd);
if (!ret)
@@ -743,7 +796,8 @@ static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI);
if (!ret)
- ret = m5mols_enable_interrupt(sd, REG_INT_AF);
+ ret = m5mols_enable_interrupt(sd,
+ REG_INT_AF | REG_INT_CAPTURE);
return ret;
}
@@ -780,7 +834,7 @@ static int m5mols_init_controls(struct m5mols_info *info)
4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
&m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
- 1, 0, V4L2_EXPOSURE_MANUAL);
+ 1, 0, V4L2_EXPOSURE_AUTO);
sd->ctrl_handler = &info->handle;
if (info->handle.error) {
@@ -809,16 +863,7 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
if (on) {
ret = m5mols_sensor_power(info, true);
if (!ret)
- ret = m5mols_sensor_armboot(sd);
- if (!ret)
- ret = m5mols_init_controls(info);
- if (ret)
- return ret;
-
- info->ffmt[M5MOLS_RESTYPE_MONITOR] =
- m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR];
- info->ffmt[M5MOLS_RESTYPE_CAPTURE] =
- m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE];
+ ret = m5mols_fw_start(sd);
return ret;
}
@@ -829,17 +874,14 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
if (!ret)
ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF);
if (!ret)
- ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS,
- REG_AF_IDLE);
- if (!ret)
- v4l2_info(sd, "Success soft-landing lens\n");
+ ret = m5mols_busy_wait(sd, SYSTEM_STATUS, REG_AF_IDLE,
+ 0xff, -1);
+ if (ret < 0)
+ v4l2_warn(sd, "Soft landing lens failed\n");
}
ret = m5mols_sensor_power(info, false);
- if (!ret) {
- v4l2_ctrl_handler_free(&info->handle);
- info->ctrl_sync = false;
- }
+ info->ctrl_sync = 0;
return ret;
}
@@ -865,52 +907,33 @@ static const struct v4l2_subdev_core_ops m5mols_core_ops = {
.log_status = m5mols_log_status,
};
+/*
+ * V4L2 subdev internal operations
+ */
+static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+
+ *format = m5mols_default_ffmt[0];
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = {
+ .open = m5mols_open,
+};
+
static const struct v4l2_subdev_ops m5mols_ops = {
.core = &m5mols_core_ops,
.pad = &m5mols_pad_ops,
.video = &m5mols_video_ops,
};
-static void m5mols_irq_work(struct work_struct *work)
-{
- struct m5mols_info *info =
- container_of(work, struct m5mols_info, work_irq);
- struct v4l2_subdev *sd = &info->sd;
- u8 reg;
- int ret;
-
- if (!is_powered(info) ||
- m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt))
- return;
-
- switch (info->interrupt & REG_INT_MASK) {
- case REG_INT_AF:
- if (!is_available_af(info))
- break;
- ret = m5mols_read_u8(sd, AF_STATUS, &reg);
- v4l2_dbg(2, m5mols_debug, sd, "AF %s\n",
- reg == REG_AF_FAIL ? "Failed" :
- reg == REG_AF_SUCCESS ? "Success" :
- reg == REG_AF_IDLE ? "Idle" : "Busy");
- break;
- case REG_INT_CAPTURE:
- if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags))
- wake_up_interruptible(&info->irq_waitq);
-
- v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n");
- break;
- default:
- v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg);
- break;
- };
-}
-
static irqreturn_t m5mols_irq_handler(int irq, void *data)
{
- struct v4l2_subdev *sd = data;
- struct m5mols_info *info = to_m5mols(sd);
+ struct m5mols_info *info = to_m5mols(data);
- schedule_work(&info->work_irq);
+ atomic_set(&info->irq_done, 1);
+ wake_up_interruptible(&info->irq_waitq);
return IRQ_HANDLED;
}
@@ -959,9 +982,11 @@ static int __devinit m5mols_probe(struct i2c_client *client,
}
sd = &info->sd;
- strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
+ strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->internal_ops = &m5mols_subdev_internal_ops;
info->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
if (ret < 0)
@@ -969,7 +994,6 @@ static int __devinit m5mols_probe(struct i2c_client *client,
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
init_waitqueue_head(&info->irq_waitq);
- INIT_WORK(&info->work_irq, m5mols_irq_work);
ret = request_irq(client->irq, m5mols_irq_handler,
IRQF_TRIGGER_RISING, MODULE_NAME, sd);
if (ret) {
@@ -977,7 +1001,20 @@ static int __devinit m5mols_probe(struct i2c_client *client,
goto out_me;
}
info->res_type = M5MOLS_RESTYPE_MONITOR;
- return 0;
+ info->ffmt[0] = m5mols_default_ffmt[0];
+ info->ffmt[1] = m5mols_default_ffmt[1];
+
+ ret = m5mols_sensor_power(info, true);
+ if (ret)
+ goto out_me;
+
+ ret = m5mols_fw_start(sd);
+ if (!ret)
+ ret = m5mols_init_controls(info);
+
+ m5mols_sensor_power(info, false);
+ if (!ret)
+ return 0;
out_me:
media_entity_cleanup(&sd->entity);
out_reg:
@@ -995,6 +1032,7 @@ static int __devexit m5mols_remove(struct i2c_client *client)
struct m5mols_info *info = to_m5mols(sd);
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
free_irq(client->irq, sd);
regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
@@ -1019,18 +1057,7 @@ static struct i2c_driver m5mols_i2c_driver = {
.id_table = m5mols_id,
};
-static int __init m5mols_mod_init(void)
-{
- return i2c_add_driver(&m5mols_i2c_driver);
-}
-
-static void __exit m5mols_mod_exit(void)
-{
- i2c_del_driver(&m5mols_i2c_driver);
-}
-
-module_init(m5mols_mod_init);
-module_exit(m5mols_mod_exit);
+module_i2c_driver(m5mols_i2c_driver);
MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>");
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h
index c755bd6edfe9..ae4aced0f9b2 100644
--- a/drivers/media/video/m5mols/m5mols_reg.h
+++ b/drivers/media/video/m5mols/m5mols_reg.h
@@ -55,39 +55,31 @@
* There is many registers between customer version address and awb one. For
* more specific contents, see definition if file m5mols.h.
*/
-#define CAT0_VER_CUSTOMER 0x00 /* customer version */
-#define CAT0_VER_PROJECT 0x01 /* project version */
-#define CAT0_VER_FIRMWARE 0x02 /* Firmware version */
-#define CAT0_VER_HARDWARE 0x04 /* Hardware version */
-#define CAT0_VER_PARAMETER 0x06 /* Parameter version */
-#define CAT0_VER_AWB 0x08 /* Auto WB version */
-#define CAT0_VER_STRING 0x0a /* string including M-5MOLS */
-#define CAT0_SYSMODE 0x0b /* SYSTEM mode register */
-#define CAT0_STATUS 0x0c /* SYSTEM mode status register */
-#define CAT0_INT_FACTOR 0x10 /* interrupt pending register */
-#define CAT0_INT_ENABLE 0x11 /* interrupt enable register */
-
-#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, CAT0_VER_CUSTOMER, 1)
-#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, CAT0_VER_PROJECT, 1)
-#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, CAT0_VER_FIRMWARE, 2)
-#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, CAT0_VER_HARDWARE, 2)
-#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, CAT0_VER_PARAMETER, 2)
-#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, CAT0_VER_AWB, 2)
-
-#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1)
+#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, 0x00, 1)
+#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, 0x01, 1)
+#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, 0x02, 2)
+#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, 0x04, 2)
+#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, 0x06, 2)
+#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, 0x08, 2)
+
+#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, 0x0b, 1)
#define REG_SYSINIT 0x00 /* SYSTEM mode */
#define REG_PARAMETER 0x01 /* PARAMETER mode */
#define REG_MONITOR 0x02 /* MONITOR mode */
#define REG_CAPTURE 0x03 /* CAPTURE mode */
#define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1)
-#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1)
+#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, 0x0a, 1)
#define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */
#define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */
#define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */
+/* SYSTEM mode status */
+#define SYSTEM_STATUS I2C_REG(CAT_SYSTEM, 0x0c, 1)
-#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1)
-#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1)
+/* Interrupt pending register */
+#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, 0x10, 1)
+/* interrupt enable register */
+#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, 0x11, 1)
#define REG_INT_MODE (1 << 0)
#define REG_INT_AF (1 << 1)
#define REG_INT_ZOOM (1 << 2)
@@ -105,20 +97,20 @@
* can handle with preview(MONITOR) resolution size/frame per second/interface
* between the sensor and the Application Processor/even the image effect.
*/
-#define CAT1_DATA_INTERFACE 0x00 /* interface between sensor and AP */
-#define CAT1_MONITOR_SIZE 0x01 /* resolution at the MONITOR mode */
-#define CAT1_MONITOR_FPS 0x02 /* frame per second at this mode */
-#define CAT1_EFFECT 0x0b /* image effects */
-#define PARM_MON_SIZE I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1)
+/* Resolution in the MONITOR mode */
+#define PARM_MON_SIZE I2C_REG(CAT_PARAM, 0x01, 1)
-#define PARM_MON_FPS I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1)
+/* Frame rate */
+#define PARM_MON_FPS I2C_REG(CAT_PARAM, 0x02, 1)
#define REG_FPS_30 0x02
-#define PARM_INTERFACE I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1)
+/* Video bus between the sensor and a host processor */
+#define PARM_INTERFACE I2C_REG(CAT_PARAM, 0x00, 1)
#define REG_INTERFACE_MIPI 0x02
-#define PARM_EFFECT I2C_REG(CAT_PARAM, CAT1_EFFECT, 1)
+/* Image effects */
+#define PARM_EFFECT I2C_REG(CAT_PARAM, 0x0b, 1)
#define REG_EFFECT_OFF 0x00
#define REG_EFFECT_NEGA 0x01
#define REG_EFFECT_EMBOSS 0x06
@@ -135,39 +127,37 @@
* another options like zoom/color effect(different with effect in PARAMETER
* mode)/anti hand shaking algorithm.
*/
-#define CAT2_ZOOM 0x01 /* set the zoom position & execute */
-#define CAT2_ZOOM_STEP 0x03 /* set the zoom step */
-#define CAT2_CFIXB 0x09 /* CB value for color effect */
-#define CAT2_CFIXR 0x0a /* CR value for color effect */
-#define CAT2_COLOR_EFFECT 0x0b /* set on/off of color effect */
-#define CAT2_CHROMA_LVL 0x0f /* set chroma level */
-#define CAT2_CHROMA_EN 0x10 /* set on/off of choroma */
-#define CAT2_EDGE_LVL 0x11 /* set sharpness level */
-#define CAT2_EDGE_EN 0x12 /* set on/off sharpness */
-#define CAT2_TONE_CTL 0x25 /* set tone color(contrast) */
-
-#define MON_ZOOM I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1)
-
-#define MON_CFIXR I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1)
-#define MON_CFIXB I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1)
+
+/* Target digital zoom position */
+#define MON_ZOOM I2C_REG(CAT_MONITOR, 0x01, 1)
+
+/* CR value for color effect */
+#define MON_CFIXR I2C_REG(CAT_MONITOR, 0x0a, 1)
+/* CB value for color effect */
+#define MON_CFIXB I2C_REG(CAT_MONITOR, 0x09, 1)
#define REG_CFIXB_SEPIA 0xd8
#define REG_CFIXR_SEPIA 0x18
-#define MON_EFFECT I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1)
+#define MON_EFFECT I2C_REG(CAT_MONITOR, 0x0b, 1)
#define REG_COLOR_EFFECT_OFF 0x00
#define REG_COLOR_EFFECT_ON 0x01
-#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1)
-#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1)
+/* Chroma enable */
+#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, 0x10, 1)
+/* Chroma level */
+#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, 0x0f, 1)
#define REG_CHROMA_OFF 0x00
#define REG_CHROMA_ON 0x01
-#define MON_EDGE_EN I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1)
-#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1)
+/* Sharpness on/off */
+#define MON_EDGE_EN I2C_REG(CAT_MONITOR, 0x12, 1)
+/* Sharpness level */
+#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, 0x11, 1)
#define REG_EDGE_OFF 0x00
#define REG_EDGE_ON 0x01
-#define MON_TONE_CTL I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1)
+/* Set color tone (contrast) */
+#define MON_TONE_CTL I2C_REG(CAT_MONITOR, 0x25, 1)
/*
* Category 3 - Auto Exposure
@@ -179,27 +169,20 @@
* different. So, this category also provide getting the max/min values. And,
* each MONITOR and CAPTURE mode has each gain/shutter/max exposure values.
*/
-#define CAT3_AE_LOCK 0x00 /* locking Auto exposure */
-#define CAT3_AE_MODE 0x01 /* set AE mode, mode means range */
-#define CAT3_ISO 0x05 /* set ISO */
-#define CAT3_EV_PRESET_MONITOR 0x0a /* EV(scenemode) preset for MONITOR */
-#define CAT3_EV_PRESET_CAPTURE 0x0b /* EV(scenemode) preset for CAPTURE */
-#define CAT3_MANUAL_GAIN_MON 0x12 /* meteoring value for the MONITOR */
-#define CAT3_MAX_GAIN_MON 0x1a /* max gain value for the MONITOR */
-#define CAT3_MANUAL_GAIN_CAP 0x26 /* meteoring value for the CAPTURE */
-#define CAT3_AE_INDEX 0x38 /* AE index */
-
-#define AE_LOCK I2C_REG(CAT_AE, CAT3_AE_LOCK, 1)
+
+/* Auto Exposure locking */
+#define AE_LOCK I2C_REG(CAT_AE, 0x00, 1)
#define REG_AE_UNLOCK 0x00
#define REG_AE_LOCK 0x01
-#define AE_MODE I2C_REG(CAT_AE, CAT3_AE_MODE, 1)
+/* Auto Exposure algorithm mode */
+#define AE_MODE I2C_REG(CAT_AE, 0x01, 1)
#define REG_AE_OFF 0x00 /* AE off */
#define REG_AE_ALL 0x01 /* calc AE in all block integral */
#define REG_AE_CENTER 0x03 /* calc AE in center weighted */
#define REG_AE_SPOT 0x06 /* calc AE in specific spot */
-#define AE_ISO I2C_REG(CAT_AE, CAT3_ISO, 1)
+#define AE_ISO I2C_REG(CAT_AE, 0x05, 1)
#define REG_ISO_AUTO 0x00
#define REG_ISO_50 0x01
#define REG_ISO_100 0x02
@@ -207,8 +190,10 @@
#define REG_ISO_400 0x04
#define REG_ISO_800 0x05
-#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1)
-#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1)
+/* EV (scenemode) preset for MONITOR */
+#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, 0x0a, 1)
+/* EV (scenemode) preset for CAPTURE */
+#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, 0x0b, 1)
#define REG_SCENE_NORMAL 0x00
#define REG_SCENE_PORTRAIT 0x01
#define REG_SCENE_LANDSCAPE 0x02
@@ -224,11 +209,14 @@
#define REG_SCENE_TEXT 0x0c
#define REG_SCENE_CANDLE 0x0d
-#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2)
-#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2)
-#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2)
+/* Manual gain in MONITOR mode */
+#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, 0x12, 2)
+/* Maximum gain in MONITOR mode */
+#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, 0x1a, 2)
+/* Manual gain in CAPTURE mode */
+#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, 0x26, 2)
-#define AE_INDEX I2C_REG(CAT_AE, CAT3_AE_INDEX, 1)
+#define AE_INDEX I2C_REG(CAT_AE, 0x38, 1)
#define REG_AE_INDEX_20_NEG 0x00
#define REG_AE_INDEX_15_NEG 0x01
#define REG_AE_INDEX_10_NEG 0x02
@@ -241,22 +229,19 @@
/*
* Category 6 - White Balance
- *
- * This category provide AWB locking/mode/preset/speed/gain bias, etc.
*/
-#define CAT6_AWB_LOCK 0x00 /* locking Auto Whitebalance */
-#define CAT6_AWB_MODE 0x02 /* set Auto or Manual */
-#define CAT6_AWB_MANUAL 0x03 /* set Manual(preset) value */
-#define AWB_LOCK I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1)
+/* Auto Whitebalance locking */
+#define AWB_LOCK I2C_REG(CAT_WB, 0x00, 1)
#define REG_AWB_UNLOCK 0x00
#define REG_AWB_LOCK 0x01
-#define AWB_MODE I2C_REG(CAT_WB, CAT6_AWB_MODE, 1)
+#define AWB_MODE I2C_REG(CAT_WB, 0x02, 1)
#define REG_AWB_AUTO 0x01 /* AWB off */
#define REG_AWB_PRESET 0x02 /* AWB preset */
-#define AWB_MANUAL I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1)
+/* Manual WB (preset) */
+#define AWB_MANUAL I2C_REG(CAT_WB, 0x03, 1)
#define REG_AWB_INCANDESCENT 0x01
#define REG_AWB_FLUORESCENT_1 0x02
#define REG_AWB_FLUORESCENT_2 0x03
@@ -269,42 +254,25 @@
/*
* Category 7 - EXIF information
*/
-#define CAT7_INFO_EXPTIME_NU 0x00
-#define CAT7_INFO_EXPTIME_DE 0x04
-#define CAT7_INFO_TV_NU 0x08
-#define CAT7_INFO_TV_DE 0x0c
-#define CAT7_INFO_AV_NU 0x10
-#define CAT7_INFO_AV_DE 0x14
-#define CAT7_INFO_BV_NU 0x18
-#define CAT7_INFO_BV_DE 0x1c
-#define CAT7_INFO_EBV_NU 0x20
-#define CAT7_INFO_EBV_DE 0x24
-#define CAT7_INFO_ISO 0x28
-#define CAT7_INFO_FLASH 0x2a
-#define CAT7_INFO_SDR 0x2c
-#define CAT7_INFO_QVAL 0x2e
-
-#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4)
-#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4)
-#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4)
-#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4)
-#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4)
-#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4)
-#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4)
-#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4)
-#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4)
-#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4)
-#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2)
-#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2)
-#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2)
-#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2)
+#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, 0x00, 4)
+#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, 0x04, 4)
+#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, 0x08, 4)
+#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, 0x0c, 4)
+#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, 0x10, 4)
+#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, 0x14, 4)
+#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, 0x18, 4)
+#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, 0x1c, 4)
+#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, 0x20, 4)
+#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, 0x24, 4)
+#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, 0x28, 2)
+#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, 0x2a, 2)
+#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, 0x2c, 2)
+#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, 0x2e, 2)
/*
* Category 9 - Face Detection
*/
-#define CAT9_FD_CTL 0x00
-
-#define FD_CTL I2C_REG(CAT_FD, CAT9_FD_CTL, 1)
+#define FD_CTL I2C_REG(CAT_FD, 0x00, 1)
#define BIT_FD_EN 0
#define BIT_FD_DRAW_FACE_FRAME 4
#define BIT_FD_DRAW_SMILE_LVL 6
@@ -314,62 +282,50 @@
/*
* Category A - Lens Parameter
*/
-#define CATA_AF_MODE 0x01
-#define CATA_AF_EXECUTE 0x02
-#define CATA_AF_STATUS 0x03
-#define CATA_AF_VERSION 0x0a
-
-#define AF_MODE I2C_REG(CAT_LENS, CATA_AF_MODE, 1)
+#define AF_MODE I2C_REG(CAT_LENS, 0x01, 1)
#define REG_AF_NORMAL 0x00 /* Normal AF, one time */
#define REG_AF_MACRO 0x01 /* Macro AF, one time */
#define REG_AF_POWEROFF 0x07
-#define AF_EXECUTE I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1)
+#define AF_EXECUTE I2C_REG(CAT_LENS, 0x02, 1)
#define REG_AF_STOP 0x00
#define REG_AF_EXE_AUTO 0x01
#define REG_AF_EXE_CAF 0x02
-#define AF_STATUS I2C_REG(CAT_LENS, CATA_AF_STATUS, 1)
+#define AF_STATUS I2C_REG(CAT_LENS, 0x03, 1)
#define REG_AF_FAIL 0x00
#define REG_AF_SUCCESS 0x02
#define REG_AF_IDLE 0x04
#define REG_AF_BUSY 0x05
-#define AF_VERSION I2C_REG(CAT_LENS, CATA_AF_VERSION, 1)
+#define AF_VERSION I2C_REG(CAT_LENS, 0x0a, 1)
/*
* Category B - CAPTURE Parameter
*/
-#define CATB_YUVOUT_MAIN 0x00
-#define CATB_MAIN_IMAGE_SIZE 0x01
-#define CATB_MCC_MODE 0x1d
-#define CATB_WDR_EN 0x2c
-#define CATB_LIGHT_CTRL 0x40
-#define CATB_FLASH_CTRL 0x41
-
-#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1)
+#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, 0x00, 1)
#define REG_YUV422 0x00
#define REG_BAYER10 0x05
#define REG_BAYER8 0x06
#define REG_JPEG 0x10
-#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1)
+#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1)
-#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1)
+#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1)
#define REG_MCC_OFF 0x00
#define REG_MCC_NORMAL 0x01
-#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1)
+#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, 0x2c, 1)
#define REG_WDR_OFF 0x00
#define REG_WDR_ON 0x01
#define REG_WDR_AUTO 0x02
-#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1)
+#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, 0x40, 1)
#define REG_LIGHT_OFF 0x00
#define REG_LIGHT_ON 0x01
#define REG_LIGHT_AUTO 0x02
-#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1)
+#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, 0x41, 1)
#define REG_FLASH_OFF 0x00
#define REG_FLASH_ON 0x01
#define REG_FLASH_AUTO 0x02
@@ -377,34 +333,29 @@
/*
* Category C - CAPTURE Control
*/
-#define CATC_CAP_MODE 0x00
-#define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi */
-#define CATC_CAP_START 0x09
-#define CATC_CAP_IMAGE_SIZE 0x0d
-#define CATC_CAP_THUMB_SIZE 0x11
-
-#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1)
+#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, 0x00, 1)
#define REG_CAP_NONE 0x00
#define REG_CAP_ANTI_SHAKE 0x02
-#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1)
+/* Select single- or multi-shot capture */
+#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, 0x06, 1)
-#define CAPC_START I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1)
+#define CAPC_START I2C_REG(CAT_CAPT_CTRL, 0x09, 1)
#define REG_CAP_START_MAIN 0x01
#define REG_CAP_START_THUMB 0x03
-#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 4)
-#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 4)
+#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, 0x0d, 4)
+#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, 0x11, 4)
/*
* Category F - Flash
*
* This mode provides functions about internal flash stuff and system startup.
*/
-#define CATF_CAM_START 0x12 /* It starts internal ARM core booting
- * after power-up */
-#define FLASH_CAM_START I2C_REG(CAT_FLASH, CATF_CAM_START, 1)
-#define REG_START_ARM_BOOT 0x01
+/* Starts internal ARM core booting after power-up */
+#define FLASH_CAM_START I2C_REG(CAT_FLASH, 0x12, 1)
+#define REG_START_ARM_BOOT 0x01 /* write value */
+#define REG_IN_FLASH_MODE 0x00 /* read value */
#endif /* M5MOLS_REG_H */
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c
index 80ec64d2d6d8..996ac34d9a89 100644
--- a/drivers/media/video/marvell-ccic/mcam-core.c
+++ b/drivers/media/video/marvell-ccic/mcam-core.c
@@ -51,7 +51,7 @@ static int delivered;
* sense.
*/
-static int alloc_bufs_at_read;
+static bool alloc_bufs_at_read;
module_param(alloc_bufs_at_read, bool, 0444);
MODULE_PARM_DESC(alloc_bufs_at_read,
"Non-zero value causes DMA buffers to be allocated when the "
@@ -73,11 +73,11 @@ MODULE_PARM_DESC(dma_buf_size,
"parameters require larger buffers, an attempt to reallocate "
"will be made.");
#else /* MCAM_MODE_VMALLOC */
-static const int alloc_bufs_at_read = 0;
+static const bool alloc_bufs_at_read = 0;
static const int n_dma_bufs = 3; /* Used by S/G_PARM */
#endif /* MCAM_MODE_VMALLOC */
-static int flip;
+static bool flip;
module_param(flip, bool, 0444);
MODULE_PARM_DESC(flip,
"If set, the sensor will be instructed to flip the image "
@@ -509,11 +509,17 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam)
buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
list_del_init(&buf->queue);
+ /*
+ * Very Bad Not Good Things happen if you don't clear
+ * C1_DESC_ENA before making any descriptor changes.
+ */
+ mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa);
mcam_reg_write(cam, REG_DESC_LEN_Y,
buf->dma_desc_nent*sizeof(struct mcam_dma_desc));
mcam_reg_write(cam, REG_DESC_LEN_U, 0);
mcam_reg_write(cam, REG_DESC_LEN_V, 0);
+ mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
cam->vb_bufs[0] = buf;
}
@@ -522,9 +528,17 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam)
*/
static void mcam_ctlr_dma_sg(struct mcam_camera *cam)
{
+ /*
+ * The list-empty condition can hit us at resume time
+ * if the buffer list was empty when the system was suspended.
+ */
+ if (list_empty(&cam->buffers)) {
+ set_bit(CF_SG_RESTART, &cam->flags);
+ return;
+ }
+
mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD);
mcam_sg_next_buffer(cam);
- mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
cam->nbufs = 3;
}
@@ -547,17 +561,16 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
struct mcam_vb_buffer *buf = cam->vb_bufs[0];
/*
- * Very Bad Not Good Things happen if you don't clear
- * C1_DESC_ENA before making any descriptor changes.
+ * If we're no longer supposed to be streaming, don't do anything.
*/
- mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
+ if (cam->state != S_STREAMING)
+ return;
/*
* If we have another buffer available, put it in and
* restart the engine.
*/
if (!list_empty(&cam->buffers)) {
mcam_sg_next_buffer(cam);
- mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
mcam_ctlr_start(cam);
/*
* Otherwise set CF_SG_RESTART and the controller will
@@ -566,6 +579,7 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
} else {
set_bit(CF_SG_RESTART, &cam->flags);
singles++;
+ cam->vb_bufs[0] = NULL;
}
/*
* Now we can give the completed frame back to user space.
@@ -661,10 +675,10 @@ static int mcam_ctlr_configure(struct mcam_camera *cam)
unsigned long flags;
spin_lock_irqsave(&cam->dev_lock, flags);
+ clear_bit(CF_SG_RESTART, &cam->flags);
cam->dma_setup(cam);
mcam_ctlr_image(cam);
mcam_set_config_needed(cam, 0);
- clear_bit(CF_SG_RESTART, &cam->flags);
spin_unlock_irqrestore(&cam->dev_lock, flags);
return 0;
}
@@ -727,7 +741,14 @@ static void mcam_ctlr_stop_dma(struct mcam_camera *cam)
mcam_ctlr_stop(cam);
cam->state = S_IDLE;
spin_unlock_irqrestore(&cam->dev_lock, flags);
- msleep(40);
+ /*
+ * This is a brutally long sleep, but experience shows that
+ * it can take the controller a while to get the message that
+ * it needs to stop grabbing frames. In particular, we can
+ * sometimes (on mmp) get a frame at the end WITHOUT the
+ * start-of-frame indication.
+ */
+ msleep(150);
if (test_bit(CF_DMA_ACTIVE, &cam->flags))
cam_err(cam, "Timeout waiting for DMA to end\n");
/* This would be bad news - what now? */
@@ -870,10 +891,12 @@ static int mcam_read_setup(struct mcam_camera *cam)
* Turn it loose.
*/
spin_lock_irqsave(&cam->dev_lock, flags);
+ clear_bit(CF_DMA_ACTIVE, &cam->flags);
mcam_reset_buffers(cam);
mcam_ctlr_irq_enable(cam);
cam->state = S_STREAMING;
- mcam_ctlr_start(cam);
+ if (!test_bit(CF_SG_RESTART, &cam->flags))
+ mcam_ctlr_start(cam);
spin_unlock_irqrestore(&cam->dev_lock, flags);
return 0;
}
@@ -911,7 +934,7 @@ static void mcam_vb_buf_queue(struct vb2_buffer *vb)
spin_lock_irqsave(&cam->dev_lock, flags);
start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers);
list_add(&mvb->queue, &cam->buffers);
- if (test_bit(CF_SG_RESTART, &cam->flags))
+ if (cam->state == S_STREAMING && test_bit(CF_SG_RESTART, &cam->flags))
mcam_sg_restart(cam);
spin_unlock_irqrestore(&cam->dev_lock, flags);
if (start)
@@ -1544,15 +1567,12 @@ static int mcam_v4l_release(struct file *filp)
{
struct mcam_camera *cam = filp->private_data;
- cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
+ cam_dbg(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
singles, delivered);
mutex_lock(&cam->s_mutex);
(cam->users)--;
- if (filp == cam->owner) {
- mcam_ctlr_stop_dma(cam);
- cam->owner = NULL;
- }
if (cam->users == 0) {
+ mcam_ctlr_stop_dma(cam);
mcam_cleanup_vb2(cam);
mcam_ctlr_power_down(cam);
if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
@@ -1677,6 +1697,8 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
if (irqs & (IRQ_EOF0 << frame)) {
mcam_frame_complete(cam, frame);
handled = 1;
+ if (cam->buffer_mode == B_DMA_sg)
+ break;
}
/*
* If a frame starts, note that we have DMA active. This
@@ -1818,11 +1840,15 @@ void mccic_shutdown(struct mcam_camera *cam)
void mccic_suspend(struct mcam_camera *cam)
{
- enum mcam_state cstate = cam->state;
+ mutex_lock(&cam->s_mutex);
+ if (cam->users > 0) {
+ enum mcam_state cstate = cam->state;
- mcam_ctlr_stop_dma(cam);
- mcam_ctlr_power_down(cam);
- cam->state = cstate;
+ mcam_ctlr_stop_dma(cam);
+ mcam_ctlr_power_down(cam);
+ cam->state = cstate;
+ }
+ mutex_unlock(&cam->s_mutex);
}
int mccic_resume(struct mcam_camera *cam)
@@ -1839,8 +1865,15 @@ int mccic_resume(struct mcam_camera *cam)
mutex_unlock(&cam->s_mutex);
set_bit(CF_CONFIG_NEEDED, &cam->flags);
- if (cam->state == S_STREAMING)
+ if (cam->state == S_STREAMING) {
+ /*
+ * If there was a buffer in the DMA engine at suspend
+ * time, put it back on the queue or we'll forget about it.
+ */
+ if (cam->buffer_mode == B_DMA_sg && cam->vb_bufs[0])
+ list_add(&cam->vb_bufs[0]->queue, &cam->buffers);
ret = mcam_read_setup(cam);
+ }
return ret;
}
#endif /* CONFIG_PM */
diff --git a/drivers/media/video/marvell-ccic/mcam-core.h b/drivers/media/video/marvell-ccic/mcam-core.h
index 917200e63255..bd6acba9fb37 100644
--- a/drivers/media/video/marvell-ccic/mcam-core.h
+++ b/drivers/media/video/marvell-ccic/mcam-core.h
@@ -107,7 +107,6 @@ struct mcam_camera {
enum mcam_state state;
unsigned long flags; /* Buffer status, mainly (dev_lock) */
int users; /* How many open FDs */
- struct file *owner; /* Who has data access (v4l2) */
/*
* Subsystem structures.
diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/video/marvell-ccic/mmp-driver.c
index fb0b124b35f3..d23552323f45 100644
--- a/drivers/media/video/marvell-ccic/mmp-driver.c
+++ b/drivers/media/video/marvell-ccic/mmp-driver.c
@@ -26,6 +26,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/list.h>
+#include <linux/pm.h>
#include "mcam-core.h"
@@ -105,6 +106,13 @@ static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
/*
* Power control.
*/
+static void mmpcam_power_up_ctlr(struct mmp_camera *cam)
+{
+ iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
+ iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
+ mdelay(1);
+}
+
static void mmpcam_power_up(struct mcam_camera *mcam)
{
struct mmp_camera *cam = mcam_to_cam(mcam);
@@ -112,9 +120,7 @@ static void mmpcam_power_up(struct mcam_camera *mcam)
/*
* Turn on power and clocks to the controller.
*/
- iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
- iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
- mdelay(1);
+ mmpcam_power_up_ctlr(cam);
/*
* Provide power to the sensor.
*/
@@ -310,10 +316,44 @@ static int mmpcam_platform_remove(struct platform_device *pdev)
return mmpcam_remove(cam);
}
+/*
+ * Suspend/resume support.
+ */
+#ifdef CONFIG_PM
+
+static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mmp_camera *cam = mmpcam_find_device(pdev);
+
+ if (state.event != PM_EVENT_SUSPEND)
+ return 0;
+ mccic_suspend(&cam->mcam);
+ return 0;
+}
+
+static int mmpcam_resume(struct platform_device *pdev)
+{
+ struct mmp_camera *cam = mmpcam_find_device(pdev);
+
+ /*
+ * Power up unconditionally just in case the core tries to
+ * touch a register even if nothing was active before; trust
+ * me, it's better this way.
+ */
+ mmpcam_power_up_ctlr(cam);
+ return mccic_resume(&cam->mcam);
+}
+
+#endif
+
static struct platform_driver mmpcam_driver = {
.probe = mmpcam_probe,
.remove = mmpcam_platform_remove,
+#ifdef CONFIG_PM
+ .suspend = mmpcam_suspend,
+ .resume = mmpcam_resume,
+#endif
.driver = {
.name = "mmp-camera",
.owner = THIS_MODULE
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index d0f538857285..82ce50721de3 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -69,12 +69,12 @@ MODULE_LICENSE("GPL");
/* module parameters */
static int opmode = OPMODE_AUTO;
int msp_debug; /* msp_debug output */
-int msp_once; /* no continuous stereo monitoring */
-int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france),
+bool msp_once; /* no continuous stereo monitoring */
+bool msp_amsound; /* hard-wire AM sound at 6.5 Hz (france),
the autoscan seems work well only with FM... */
int msp_standard = 1; /* Override auto detect of audio msp_standard,
if needed. */
-int msp_dolby;
+bool msp_dolby;
int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
(msp34xxg only) 0x00a0-0x03c0 */
@@ -881,18 +881,7 @@ static struct i2c_driver msp_driver = {
.id_table = msp_id,
};
-static __init int init_msp(void)
-{
- return i2c_add_driver(&msp_driver);
-}
-
-static __exit void exit_msp(void)
-{
- i2c_del_driver(&msp_driver);
-}
-
-module_init(init_msp);
-module_exit(exit_msp);
+module_i2c_driver(msp_driver);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h
index 831e8db4368c..fbe5e0715f93 100644
--- a/drivers/media/video/msp3400-driver.h
+++ b/drivers/media/video/msp3400-driver.h
@@ -44,10 +44,10 @@
/* module parameters */
extern int msp_debug;
-extern int msp_once;
-extern int msp_amsound;
+extern bool msp_once;
+extern bool msp_amsound;
extern int msp_standard;
-extern int msp_dolby;
+extern bool msp_dolby;
extern int msp_stereo_thresh;
struct msp_state {
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index e2b1029b16cd..7e648183f157 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -109,14 +109,13 @@ static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
static int reg_read(struct i2c_client *client, const u8 reg)
{
- s32 data = i2c_smbus_read_word_data(client, reg);
- return data < 0 ? data : swab16(data);
+ return i2c_smbus_read_word_swapped(client, reg);
}
static int reg_write(struct i2c_client *client, const u8 reg,
const u16 data)
{
- return i2c_smbus_write_word_data(client, reg, swab16(data));
+ return i2c_smbus_write_word_swapped(client, reg, data);
}
static int reg_set(struct i2c_client *client, const u8 reg,
@@ -731,18 +730,7 @@ static struct i2c_driver mt9m001_i2c_driver = {
.id_table = mt9m001_id,
};
-static int __init mt9m001_mod_init(void)
-{
- return i2c_add_driver(&mt9m001_i2c_driver);
-}
-
-static void __exit mt9m001_mod_exit(void)
-{
- i2c_del_driver(&mt9m001_i2c_driver);
-}
-
-module_init(mt9m001_mod_init);
-module_exit(mt9m001_mod_exit);
+module_i2c_driver(mt9m001_i2c_driver);
MODULE_DESCRIPTION("Micron MT9M001 Camera driver");
MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
diff --git a/drivers/media/video/mt9m032.c b/drivers/media/video/mt9m032.c
new file mode 100644
index 000000000000..7636672c3548
--- /dev/null
+++ b/drivers/media/video/mt9m032.c
@@ -0,0 +1,868 @@
+/*
+ * Driver for MT9M032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010-2011 Lund Engineering
+ * Contact: Gil Lund <gwlund@lundeng.com>
+ * Author: Martin Hostettler <martin@neutronstar.dyndns.org>
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/media-entity.h>
+#include <media/mt9m032.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "aptina-pll.h"
+
+/*
+ * width and height include active boundary and black parts
+ *
+ * column 0- 15 active boundary
+ * column 16-1455 image
+ * column 1456-1471 active boundary
+ * column 1472-1599 black
+ *
+ * row 0- 51 black
+ * row 53- 59 active boundary
+ * row 60-1139 image
+ * row 1140-1147 active boundary
+ * row 1148-1151 black
+ */
+
+#define MT9M032_PIXEL_ARRAY_WIDTH 1600
+#define MT9M032_PIXEL_ARRAY_HEIGHT 1152
+
+#define MT9M032_CHIP_VERSION 0x00
+#define MT9M032_CHIP_VERSION_VALUE 0x1402
+#define MT9M032_ROW_START 0x01
+#define MT9M032_ROW_START_MIN 0
+#define MT9M032_ROW_START_MAX 1152
+#define MT9M032_ROW_START_DEF 60
+#define MT9M032_COLUMN_START 0x02
+#define MT9M032_COLUMN_START_MIN 0
+#define MT9M032_COLUMN_START_MAX 1600
+#define MT9M032_COLUMN_START_DEF 16
+#define MT9M032_ROW_SIZE 0x03
+#define MT9M032_ROW_SIZE_MIN 32
+#define MT9M032_ROW_SIZE_MAX 1152
+#define MT9M032_ROW_SIZE_DEF 1080
+#define MT9M032_COLUMN_SIZE 0x04
+#define MT9M032_COLUMN_SIZE_MIN 32
+#define MT9M032_COLUMN_SIZE_MAX 1600
+#define MT9M032_COLUMN_SIZE_DEF 1440
+#define MT9M032_HBLANK 0x05
+#define MT9M032_VBLANK 0x06
+#define MT9M032_VBLANK_MAX 0x7ff
+#define MT9M032_SHUTTER_WIDTH_HIGH 0x08
+#define MT9M032_SHUTTER_WIDTH_LOW 0x09
+#define MT9M032_SHUTTER_WIDTH_MIN 1
+#define MT9M032_SHUTTER_WIDTH_MAX 1048575
+#define MT9M032_SHUTTER_WIDTH_DEF 1943
+#define MT9M032_PIX_CLK_CTRL 0x0a
+#define MT9M032_PIX_CLK_CTRL_INV_PIXCLK 0x8000
+#define MT9M032_RESTART 0x0b
+#define MT9M032_RESET 0x0d
+#define MT9M032_PLL_CONFIG1 0x11
+#define MT9M032_PLL_CONFIG1_OUTDIV_MASK 0x3f
+#define MT9M032_PLL_CONFIG1_MUL_SHIFT 8
+#define MT9M032_READ_MODE1 0x1e
+#define MT9M032_READ_MODE2 0x20
+#define MT9M032_READ_MODE2_VFLIP_SHIFT 15
+#define MT9M032_READ_MODE2_HFLIP_SHIFT 14
+#define MT9M032_READ_MODE2_ROW_BLC 0x40
+#define MT9M032_GAIN_GREEN1 0x2b
+#define MT9M032_GAIN_BLUE 0x2c
+#define MT9M032_GAIN_RED 0x2d
+#define MT9M032_GAIN_GREEN2 0x2e
+
+/* write only */
+#define MT9M032_GAIN_ALL 0x35
+#define MT9M032_GAIN_DIGITAL_MASK 0x7f
+#define MT9M032_GAIN_DIGITAL_SHIFT 8
+#define MT9M032_GAIN_AMUL_SHIFT 6
+#define MT9M032_GAIN_ANALOG_MASK 0x3f
+#define MT9M032_FORMATTER1 0x9e
+#define MT9M032_FORMATTER2 0x9f
+#define MT9M032_FORMATTER2_DOUT_EN 0x1000
+#define MT9M032_FORMATTER2_PIXCLK_EN 0x2000
+
+/*
+ * The available MT9M032 datasheet is missing documentation for register 0x10
+ * MT9P031 seems to be close enough, so use constants from that datasheet for
+ * now.
+ * But keep the name MT9P031 to remind us, that this isn't really confirmed
+ * for this sensor.
+ */
+#define MT9P031_PLL_CONTROL 0x10
+#define MT9P031_PLL_CONTROL_PWROFF 0x0050
+#define MT9P031_PLL_CONTROL_PWRON 0x0051
+#define MT9P031_PLL_CONTROL_USEPLL 0x0052
+#define MT9P031_PLL_CONFIG2 0x11
+#define MT9P031_PLL_CONFIG2_P1_DIV_MASK 0x1f
+
+struct mt9m032 {
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+ struct mt9m032_platform_data *pdata;
+
+ unsigned int pix_clock;
+
+ struct v4l2_ctrl_handler ctrls;
+ struct {
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ };
+
+ struct mutex lock; /* Protects streaming, format, interval and crop */
+
+ bool streaming;
+
+ struct v4l2_mbus_framefmt format;
+ struct v4l2_rect crop;
+ struct v4l2_fract frame_interval;
+};
+
+#define to_mt9m032(sd) container_of(sd, struct mt9m032, subdev)
+#define to_dev(sensor) \
+ (&((struct i2c_client *)v4l2_get_subdevdata(&(sensor)->subdev))->dev)
+
+static int mt9m032_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int mt9m032_write(struct i2c_client *client, u8 reg, const u16 data)
+{
+ return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static u32 mt9m032_row_time(struct mt9m032 *sensor, unsigned int width)
+{
+ unsigned int effective_width;
+ u32 ns;
+
+ effective_width = width + 716; /* empirical value */
+ ns = div_u64(1000000000ULL * effective_width, sensor->pix_clock);
+ dev_dbg(to_dev(sensor), "MT9M032 line time: %u ns\n", ns);
+ return ns;
+}
+
+static int mt9m032_update_timing(struct mt9m032 *sensor,
+ struct v4l2_fract *interval)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+ struct v4l2_rect *crop = &sensor->crop;
+ unsigned int min_vblank;
+ unsigned int vblank;
+ u32 row_time;
+
+ if (!interval)
+ interval = &sensor->frame_interval;
+
+ row_time = mt9m032_row_time(sensor, crop->width);
+
+ vblank = div_u64(1000000000ULL * interval->numerator,
+ (u64)row_time * interval->denominator)
+ - crop->height;
+
+ if (vblank > MT9M032_VBLANK_MAX) {
+ /* hardware limits to 11 bit values */
+ interval->denominator = 1000;
+ interval->numerator =
+ div_u64((crop->height + MT9M032_VBLANK_MAX) *
+ (u64)row_time * interval->denominator,
+ 1000000000ULL);
+ vblank = div_u64(1000000000ULL * interval->numerator,
+ (u64)row_time * interval->denominator)
+ - crop->height;
+ }
+ /* enforce minimal 1.6ms blanking time. */
+ min_vblank = 1600000 / row_time;
+ vblank = clamp_t(unsigned int, vblank, min_vblank, MT9M032_VBLANK_MAX);
+
+ return mt9m032_write(client, MT9M032_VBLANK, vblank);
+}
+
+static int mt9m032_update_geom_timing(struct mt9m032 *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+ int ret;
+
+ ret = mt9m032_write(client, MT9M032_COLUMN_SIZE,
+ sensor->crop.width - 1);
+ if (!ret)
+ ret = mt9m032_write(client, MT9M032_ROW_SIZE,
+ sensor->crop.height - 1);
+ if (!ret)
+ ret = mt9m032_write(client, MT9M032_COLUMN_START,
+ sensor->crop.left);
+ if (!ret)
+ ret = mt9m032_write(client, MT9M032_ROW_START,
+ sensor->crop.top);
+ if (!ret)
+ ret = mt9m032_update_timing(sensor, NULL);
+ return ret;
+}
+
+static int update_formatter2(struct mt9m032 *sensor, bool streaming)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+ u16 reg_val = MT9M032_FORMATTER2_DOUT_EN
+ | 0x0070; /* parts reserved! */
+ /* possibly for changing to 14-bit mode */
+
+ if (streaming)
+ reg_val |= MT9M032_FORMATTER2_PIXCLK_EN; /* pixclock enable */
+
+ return mt9m032_write(client, MT9M032_FORMATTER2, reg_val);
+}
+
+static int mt9m032_setup_pll(struct mt9m032 *sensor)
+{
+ static const struct aptina_pll_limits limits = {
+ .ext_clock_min = 8000000,
+ .ext_clock_max = 16500000,
+ .int_clock_min = 2000000,
+ .int_clock_max = 24000000,
+ .out_clock_min = 322000000,
+ .out_clock_max = 693000000,
+ .pix_clock_max = 99000000,
+ .n_min = 1,
+ .n_max = 64,
+ .m_min = 16,
+ .m_max = 255,
+ .p1_min = 1,
+ .p1_max = 128,
+ };
+
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+ struct mt9m032_platform_data *pdata = sensor->pdata;
+ struct aptina_pll pll;
+ int ret;
+
+ pll.ext_clock = pdata->ext_clock;
+ pll.pix_clock = pdata->pix_clock;
+
+ ret = aptina_pll_calculate(&client->dev, &limits, &pll);
+ if (ret < 0)
+ return ret;
+
+ sensor->pix_clock = pdata->pix_clock;
+
+ ret = mt9m032_write(client, MT9M032_PLL_CONFIG1,
+ (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT)
+ | (pll.p1 - 1));
+ if (!ret)
+ ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1);
+ if (!ret)
+ ret = mt9m032_write(client, MT9P031_PLL_CONTROL,
+ MT9P031_PLL_CONTROL_PWRON |
+ MT9P031_PLL_CONTROL_USEPLL);
+ if (!ret) /* more reserved, Continuous, Master Mode */
+ ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006);
+ if (!ret) /* Set 14-bit mode, select 7 divider */
+ ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e);
+
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Subdev pad operations
+ */
+
+static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index != 0)
+ return -EINVAL;
+
+ code->code = V4L2_MBUS_FMT_Y8_1X8;
+ return 0;
+}
+
+static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index != 0 || fse->code != V4L2_MBUS_FMT_Y8_1X8)
+ return -EINVAL;
+
+ fse->min_width = MT9M032_COLUMN_SIZE_DEF;
+ fse->max_width = MT9M032_COLUMN_SIZE_DEF;
+ fse->min_height = MT9M032_ROW_SIZE_DEF;
+ fse->max_height = MT9M032_ROW_SIZE_DEF;
+
+ return 0;
+}
+
+/**
+ * __mt9m032_get_pad_crop() - get crop rect
+ * @sensor: pointer to the sensor struct
+ * @fh: file handle for getting the try crop rect from
+ * @which: select try or active crop rect
+ *
+ * Returns a pointer the current active or fh relative try crop rect
+ */
+static struct v4l2_rect *
+__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
+ enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(fh, 0);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &sensor->crop;
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * __mt9m032_get_pad_format() - get format
+ * @sensor: pointer to the sensor struct
+ * @fh: file handle for getting the try format from
+ * @which: select try or active format
+ *
+ * Returns a pointer the current active or fh relative try format
+ */
+static struct v4l2_mbus_framefmt *
+__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
+ enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(fh, 0);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &sensor->format;
+ default:
+ return NULL;
+ }
+}
+
+static int mt9m032_get_pad_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mt9m032 *sensor = to_mt9m032(subdev);
+
+ mutex_lock(&sensor->lock);
+ fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which);
+ mutex_unlock(&sensor->lock);
+
+ return 0;
+}
+
+static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mt9m032 *sensor = to_mt9m032(subdev);
+ int ret;
+
+ mutex_lock(&sensor->lock);
+
+ if (sensor->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ ret = -EBUSY;
+ goto done;
+ }
+
+ /* Scaling is not supported, the format is thus fixed. */
+ ret = mt9m032_get_pad_format(subdev, fh, fmt);
+
+done:
+ mutex_lock(&sensor->lock);
+ return ret;
+}
+
+static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct mt9m032 *sensor = to_mt9m032(subdev);
+
+ mutex_lock(&sensor->lock);
+ crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which);
+ mutex_unlock(&sensor->lock);
+
+ return 0;
+}
+
+static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct mt9m032 *sensor = to_mt9m032(subdev);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *__crop;
+ struct v4l2_rect rect;
+ int ret = 0;
+
+ mutex_lock(&sensor->lock);
+
+ if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ ret = -EBUSY;
+ goto done;
+ }
+
+ /* Clamp the crop rectangle boundaries and align them to a multiple of 2
+ * pixels to ensure a GRBG Bayer pattern.
+ */
+ rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN,
+ MT9M032_COLUMN_START_MAX);
+ rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN,
+ MT9M032_ROW_START_MAX);
+ rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN,
+ MT9M032_COLUMN_SIZE_MAX);
+ rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN,
+ MT9M032_ROW_SIZE_MAX);
+
+ rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left);
+ rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
+
+ __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which);
+
+ if (rect.width != __crop->width || rect.height != __crop->height) {
+ /* Reset the output image size if the crop rectangle size has
+ * been modified.
+ */
+ format = __mt9m032_get_pad_format(sensor, fh, crop->which);
+ format->width = rect.width;
+ format->height = rect.height;
+ }
+
+ *__crop = rect;
+ crop->rect = rect;
+
+ if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ ret = mt9m032_update_geom_timing(sensor);
+
+done:
+ mutex_unlock(&sensor->lock);
+ return ret;
+}
+
+static int mt9m032_get_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct mt9m032 *sensor = to_mt9m032(subdev);
+
+ mutex_lock(&sensor->lock);
+ memset(fi, 0, sizeof(*fi));
+ fi->interval = sensor->frame_interval;
+ mutex_unlock(&sensor->lock);
+
+ return 0;
+}
+
+static int mt9m032_set_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct mt9m032 *sensor = to_mt9m032(subdev);
+ int ret;
+
+ mutex_lock(&sensor->lock);
+
+ if (sensor->streaming) {
+ ret = -EBUSY;
+ goto done;
+ }
+
+ /* Avoid divisions by 0. */
+ if (fi->interval.denominator == 0)
+ fi->interval.denominator = 1;
+
+ ret = mt9m032_update_timing(sensor, &fi->interval);
+ if (!ret)
+ sensor->frame_interval = fi->interval;
+
+done:
+ mutex_unlock(&sensor->lock);
+ return ret;
+}
+
+static int mt9m032_s_stream(struct v4l2_subdev *subdev, int streaming)
+{
+ struct mt9m032 *sensor = to_mt9m032(subdev);
+ int ret;
+
+ mutex_lock(&sensor->lock);
+ ret = update_formatter2(sensor, streaming);
+ if (!ret)
+ sensor->streaming = streaming;
+ mutex_unlock(&sensor->lock);
+
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m032_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct mt9m032 *sensor = to_mt9m032(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+ int val;
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ val = mt9m032_read(client, reg->reg);
+ if (val < 0)
+ return -EIO;
+
+ reg->size = 2;
+ reg->val = val;
+
+ return 0;
+}
+
+static int mt9m032_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct mt9m032 *sensor = to_mt9m032(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+
+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match.addr != client->addr)
+ return -ENODEV;
+
+ return mt9m032_write(client, reg->reg, reg->val);
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+static int update_read_mode2(struct mt9m032 *sensor, bool vflip, bool hflip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+ int reg_val = (vflip << MT9M032_READ_MODE2_VFLIP_SHIFT)
+ | (hflip << MT9M032_READ_MODE2_HFLIP_SHIFT)
+ | MT9M032_READ_MODE2_ROW_BLC
+ | 0x0007;
+
+ return mt9m032_write(client, MT9M032_READ_MODE2, reg_val);
+}
+
+static int mt9m032_set_gain(struct mt9m032 *sensor, s32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+ int digital_gain_val; /* in 1/8th (0..127) */
+ int analog_mul; /* 0 or 1 */
+ int analog_gain_val; /* in 1/16th. (0..63) */
+ u16 reg_val;
+
+ digital_gain_val = 51; /* from setup example */
+
+ if (val < 63) {
+ analog_mul = 0;
+ analog_gain_val = val;
+ } else {
+ analog_mul = 1;
+ analog_gain_val = val / 2;
+ }
+
+ /* a_gain = (1 + analog_mul) + (analog_gain_val + 1) / 16 */
+ /* overall_gain = a_gain * (1 + digital_gain_val / 8) */
+
+ reg_val = ((digital_gain_val & MT9M032_GAIN_DIGITAL_MASK)
+ << MT9M032_GAIN_DIGITAL_SHIFT)
+ | ((analog_mul & 1) << MT9M032_GAIN_AMUL_SHIFT)
+ | (analog_gain_val & MT9M032_GAIN_ANALOG_MASK);
+
+ return mt9m032_write(client, MT9M032_GAIN_ALL, reg_val);
+}
+
+static int mt9m032_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+ if (ctrl->id == V4L2_CID_GAIN && ctrl->val >= 63) {
+ /* round because of multiplier used for values >= 63 */
+ ctrl->val &= ~1;
+ }
+
+ return 0;
+}
+
+static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9m032 *sensor =
+ container_of(ctrl->handler, struct mt9m032, ctrls);
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ return mt9m032_set_gain(sensor, ctrl->val);
+
+ case V4L2_CID_HFLIP:
+ /* case V4L2_CID_VFLIP: -- In the same cluster */
+ return update_read_mode2(sensor, sensor->vflip->val,
+ sensor->hflip->val);
+
+ case V4L2_CID_EXPOSURE:
+ ret = mt9m032_write(client, MT9M032_SHUTTER_WIDTH_HIGH,
+ (ctrl->val >> 16) & 0xffff);
+ if (ret < 0)
+ return ret;
+
+ return mt9m032_write(client, MT9M032_SHUTTER_WIDTH_LOW,
+ ctrl->val & 0xffff);
+ }
+
+ return 0;
+}
+
+static struct v4l2_ctrl_ops mt9m032_ctrl_ops = {
+ .s_ctrl = mt9m032_set_ctrl,
+ .try_ctrl = mt9m032_try_ctrl,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops mt9m032_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9m032_g_register,
+ .s_register = mt9m032_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops mt9m032_video_ops = {
+ .s_stream = mt9m032_s_stream,
+ .g_frame_interval = mt9m032_get_frame_interval,
+ .s_frame_interval = mt9m032_set_frame_interval,
+};
+
+static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = {
+ .enum_mbus_code = mt9m032_enum_mbus_code,
+ .enum_frame_size = mt9m032_enum_frame_size,
+ .get_fmt = mt9m032_get_pad_format,
+ .set_fmt = mt9m032_set_pad_format,
+ .set_crop = mt9m032_set_pad_crop,
+ .get_crop = mt9m032_get_pad_crop,
+};
+
+static const struct v4l2_subdev_ops mt9m032_ops = {
+ .core = &mt9m032_core_ops,
+ .video = &mt9m032_video_ops,
+ .pad = &mt9m032_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9m032_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct mt9m032 *sensor;
+ int chip_version;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&client->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ if (!client->dev.platform_data)
+ return -ENODEV;
+
+ sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+ if (sensor == NULL)
+ return -ENOMEM;
+
+ mutex_init(&sensor->lock);
+
+ sensor->pdata = client->dev.platform_data;
+
+ v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops);
+ sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ chip_version = mt9m032_read(client, MT9M032_CHIP_VERSION);
+ if (chip_version != MT9M032_CHIP_VERSION_VALUE) {
+ dev_err(&client->dev, "MT9M032 not detected, wrong version "
+ "0x%04x\n", chip_version);
+ ret = -ENODEV;
+ goto error_sensor;
+ }
+
+ dev_info(&client->dev, "MT9M032 detected at address 0x%02x\n",
+ client->addr);
+
+ sensor->frame_interval.numerator = 1;
+ sensor->frame_interval.denominator = 30;
+
+ sensor->crop.left = MT9M032_COLUMN_START_DEF;
+ sensor->crop.top = MT9M032_ROW_START_DEF;
+ sensor->crop.width = MT9M032_COLUMN_SIZE_DEF;
+ sensor->crop.height = MT9M032_ROW_SIZE_DEF;
+
+ sensor->format.width = sensor->crop.width;
+ sensor->format.height = sensor->crop.height;
+ sensor->format.code = V4L2_MBUS_FMT_Y8_1X8;
+ sensor->format.field = V4L2_FIELD_NONE;
+ sensor->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+ v4l2_ctrl_handler_init(&sensor->ctrls, 4);
+
+ v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+ V4L2_CID_GAIN, 0, 127, 1, 64);
+
+ sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls,
+ &mt9m032_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls,
+ &mt9m032_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+ V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN,
+ MT9M032_SHUTTER_WIDTH_MAX, 1,
+ MT9M032_SHUTTER_WIDTH_DEF);
+
+ if (sensor->ctrls.error) {
+ ret = sensor->ctrls.error;
+ dev_err(&client->dev, "control initialization error %d\n", ret);
+ goto error_ctrl;
+ }
+
+ v4l2_ctrl_cluster(2, &sensor->hflip);
+
+ sensor->subdev.ctrl_handler = &sensor->ctrls;
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&sensor->subdev.entity, 1, &sensor->pad, 0);
+ if (ret < 0)
+ goto error_ctrl;
+
+ ret = mt9m032_write(client, MT9M032_RESET, 1); /* reset on */
+ if (ret < 0)
+ goto error_entity;
+ mt9m032_write(client, MT9M032_RESET, 0); /* reset off */
+ if (ret < 0)
+ goto error_entity;
+
+ ret = mt9m032_setup_pll(sensor);
+ if (ret < 0)
+ goto error_entity;
+ usleep_range(10000, 11000);
+
+ ret = v4l2_ctrl_handler_setup(&sensor->ctrls);
+ if (ret < 0)
+ goto error_entity;
+
+ /* SIZE */
+ ret = mt9m032_update_geom_timing(sensor);
+ if (ret < 0)
+ goto error_entity;
+
+ ret = mt9m032_write(client, 0x41, 0x0000); /* reserved !!! */
+ if (ret < 0)
+ goto error_entity;
+ ret = mt9m032_write(client, 0x42, 0x0003); /* reserved !!! */
+ if (ret < 0)
+ goto error_entity;
+ ret = mt9m032_write(client, 0x43, 0x0003); /* reserved !!! */
+ if (ret < 0)
+ goto error_entity;
+ ret = mt9m032_write(client, 0x7f, 0x0000); /* reserved !!! */
+ if (ret < 0)
+ goto error_entity;
+ if (sensor->pdata->invert_pixclock) {
+ ret = mt9m032_write(client, MT9M032_PIX_CLK_CTRL,
+ MT9M032_PIX_CLK_CTRL_INV_PIXCLK);
+ if (ret < 0)
+ goto error_entity;
+ }
+
+ ret = mt9m032_write(client, MT9M032_RESTART, 1); /* Restart on */
+ if (ret < 0)
+ goto error_entity;
+ msleep(100);
+ ret = mt9m032_write(client, MT9M032_RESTART, 0); /* Restart off */
+ if (ret < 0)
+ goto error_entity;
+ msleep(100);
+ ret = update_formatter2(sensor, false);
+ if (ret < 0)
+ goto error_entity;
+
+ return ret;
+
+error_entity:
+ media_entity_cleanup(&sensor->subdev.entity);
+error_ctrl:
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+error_sensor:
+ mutex_destroy(&sensor->lock);
+ kfree(sensor);
+ return ret;
+}
+
+static int mt9m032_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct mt9m032 *sensor = to_mt9m032(subdev);
+
+ v4l2_device_unregister_subdev(&sensor->subdev);
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+ media_entity_cleanup(&sensor->subdev.entity);
+ mutex_destroy(&sensor->lock);
+ kfree(sensor);
+ return 0;
+}
+
+static const struct i2c_device_id mt9m032_id_table[] = {
+ { MT9M032_NAME, 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, mt9m032_id_table);
+
+static struct i2c_driver mt9m032_i2c_driver = {
+ .driver = {
+ .name = MT9M032_NAME,
+ },
+ .probe = mt9m032_probe,
+ .remove = mt9m032_remove,
+ .id_table = mt9m032_id_table,
+};
+
+module_i2c_driver(mt9m032_i2c_driver);
+
+MODULE_AUTHOR("Martin Hostettler <martin@neutronstar.dyndns.org>");
+MODULE_DESCRIPTION("MT9M032 camera sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 398f96ffd35e..b0c529964329 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -139,25 +139,52 @@
#define MT9M111_MAX_HEIGHT 1024
#define MT9M111_MAX_WIDTH 1280
+struct mt9m111_context {
+ u16 read_mode;
+ u16 blanking_h;
+ u16 blanking_v;
+ u16 reducer_xzoom;
+ u16 reducer_yzoom;
+ u16 reducer_xsize;
+ u16 reducer_ysize;
+ u16 output_fmt_ctrl2;
+ u16 control;
+};
+
+static struct mt9m111_context context_a = {
+ .read_mode = MT9M111_READ_MODE_A,
+ .blanking_h = MT9M111_HORIZONTAL_BLANKING_A,
+ .blanking_v = MT9M111_VERTICAL_BLANKING_A,
+ .reducer_xzoom = MT9M111_REDUCER_XZOOM_A,
+ .reducer_yzoom = MT9M111_REDUCER_YZOOM_A,
+ .reducer_xsize = MT9M111_REDUCER_XSIZE_A,
+ .reducer_ysize = MT9M111_REDUCER_YSIZE_A,
+ .output_fmt_ctrl2 = MT9M111_OUTPUT_FORMAT_CTRL2_A,
+ .control = MT9M111_CTXT_CTRL_RESTART,
+};
+
+static struct mt9m111_context context_b = {
+ .read_mode = MT9M111_READ_MODE_B,
+ .blanking_h = MT9M111_HORIZONTAL_BLANKING_B,
+ .blanking_v = MT9M111_VERTICAL_BLANKING_B,
+ .reducer_xzoom = MT9M111_REDUCER_XZOOM_B,
+ .reducer_yzoom = MT9M111_REDUCER_YZOOM_B,
+ .reducer_xsize = MT9M111_REDUCER_XSIZE_B,
+ .reducer_ysize = MT9M111_REDUCER_YSIZE_B,
+ .output_fmt_ctrl2 = MT9M111_OUTPUT_FORMAT_CTRL2_B,
+ .control = MT9M111_CTXT_CTRL_RESTART |
+ MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B |
+ MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B |
+ MT9M111_CTXT_CTRL_READ_MODE_B | MT9M111_CTXT_CTRL_VBLANK_SEL_B |
+ MT9M111_CTXT_CTRL_HBLANK_SEL_B,
+};
+
/* MT9M111 has only one fixed colorspace per pixelcode */
struct mt9m111_datafmt {
enum v4l2_mbus_pixelcode code;
enum v4l2_colorspace colorspace;
};
-/* Find a data format by a pixel code in an array */
-static const struct mt9m111_datafmt *mt9m111_find_datafmt(
- enum v4l2_mbus_pixelcode code, const struct mt9m111_datafmt *fmt,
- int n)
-{
- int i;
- for (i = 0; i < n; i++)
- if (fmt[i].code == code)
- return fmt + i;
-
- return NULL;
-}
-
static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
{V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
@@ -173,27 +200,35 @@ static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
};
-enum mt9m111_context {
- HIGHPOWER = 0,
- LOWPOWER,
-};
-
struct mt9m111 {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl *gain;
int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
* from v4l2-chip-ident.h */
- enum mt9m111_context context;
- struct v4l2_rect rect;
+ struct mt9m111_context *ctx;
+ struct v4l2_rect rect; /* cropping rectangle */
+ int width; /* output */
+ int height; /* sizes */
struct mutex power_lock; /* lock to protect power_count */
int power_count;
const struct mt9m111_datafmt *fmt;
int lastpage; /* PageMap cache value */
unsigned char datawidth;
- unsigned int powered:1;
};
+/* Find a data format by a pixel code */
+static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111,
+ enum v4l2_mbus_pixelcode code)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(mt9m111_colour_fmts); i++)
+ if (mt9m111_colour_fmts[i].code == code)
+ return mt9m111_colour_fmts + i;
+
+ return mt9m111->fmt;
+}
+
static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
{
return container_of(i2c_get_clientdata(client), struct mt9m111, subdev);
@@ -211,7 +246,7 @@ static int reg_page_map_set(struct i2c_client *client, const u16 reg)
if (page > 2)
return -EINVAL;
- ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page));
+ ret = i2c_smbus_write_word_swapped(client, MT9M111_PAGE_MAP, page);
if (!ret)
mt9m111->lastpage = page;
return ret;
@@ -223,7 +258,7 @@ static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
ret = reg_page_map_set(client, reg);
if (!ret)
- ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff));
+ ret = i2c_smbus_read_word_swapped(client, reg & 0xff);
dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret);
return ret;
@@ -236,8 +271,7 @@ static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
ret = reg_page_map_set(client, reg);
if (!ret)
- ret = i2c_smbus_write_word_data(client, reg & 0xff,
- swab16(data));
+ ret = i2c_smbus_write_word_swapped(client, reg & 0xff, data);
dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
return ret;
}
@@ -276,76 +310,63 @@ static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg,
}
static int mt9m111_set_context(struct mt9m111 *mt9m111,
- enum mt9m111_context ctxt)
+ struct mt9m111_context *ctx)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
- | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
- | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
- | MT9M111_CTXT_CTRL_VBLANK_SEL_B
- | MT9M111_CTXT_CTRL_HBLANK_SEL_B;
- int valA = MT9M111_CTXT_CTRL_RESTART;
-
- if (ctxt == HIGHPOWER)
- return reg_write(CONTEXT_CONTROL, valB);
- else
- return reg_write(CONTEXT_CONTROL, valA);
+ return reg_write(CONTEXT_CONTROL, ctx->control);
}
-static int mt9m111_setup_rect(struct mt9m111 *mt9m111,
- struct v4l2_rect *rect)
+static int mt9m111_setup_rect_ctx(struct mt9m111 *mt9m111,
+ struct mt9m111_context *ctx, struct v4l2_rect *rect,
+ unsigned int width, unsigned int height)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- int ret, is_raw_format;
- int width = rect->width;
- int height = rect->height;
+ int ret = mt9m111_reg_write(client, ctx->reducer_xzoom, rect->width);
+ if (!ret)
+ ret = mt9m111_reg_write(client, ctx->reducer_yzoom, rect->height);
+ if (!ret)
+ ret = mt9m111_reg_write(client, ctx->reducer_xsize, width);
+ if (!ret)
+ ret = mt9m111_reg_write(client, ctx->reducer_ysize, height);
+ return ret;
+}
- if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
- mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE)
- is_raw_format = 1;
- else
- is_raw_format = 0;
+static int mt9m111_setup_geometry(struct mt9m111 *mt9m111, struct v4l2_rect *rect,
+ int width, int height, enum v4l2_mbus_pixelcode code)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ int ret;
ret = reg_write(COLUMN_START, rect->left);
if (!ret)
ret = reg_write(ROW_START, rect->top);
- if (is_raw_format) {
- if (!ret)
- ret = reg_write(WINDOW_WIDTH, width);
- if (!ret)
- ret = reg_write(WINDOW_HEIGHT, height);
- } else {
- if (!ret)
- ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH);
- if (!ret)
- ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT);
- if (!ret)
- ret = reg_write(REDUCER_XSIZE_B, width);
- if (!ret)
- ret = reg_write(REDUCER_YSIZE_B, height);
- if (!ret)
- ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH);
- if (!ret)
- ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT);
+ if (!ret)
+ ret = reg_write(WINDOW_WIDTH, rect->width);
+ if (!ret)
+ ret = reg_write(WINDOW_HEIGHT, rect->height);
+
+ if (code != V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+ /* IFP in use, down-scaling possible */
if (!ret)
- ret = reg_write(REDUCER_XSIZE_A, width);
+ ret = mt9m111_setup_rect_ctx(mt9m111, &context_b,
+ rect, width, height);
if (!ret)
- ret = reg_write(REDUCER_YSIZE_A, height);
+ ret = mt9m111_setup_rect_ctx(mt9m111, &context_a,
+ rect, width, height);
}
+ dev_dbg(&client->dev, "%s(%x): %ux%u@%u:%u -> %ux%u = %d\n",
+ __func__, code, rect->width, rect->height, rect->left, rect->top,
+ width, height, ret);
+
return ret;
}
static int mt9m111_enable(struct mt9m111 *mt9m111)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- int ret;
-
- ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE);
- if (!ret)
- mt9m111->powered = 1;
- return ret;
+ return reg_write(RESET, MT9M111_RESET_CHIP_ENABLE);
}
static int mt9m111_reset(struct mt9m111 *mt9m111)
@@ -363,43 +384,41 @@ static int mt9m111_reset(struct mt9m111 *mt9m111)
return ret;
}
-static int mt9m111_make_rect(struct mt9m111 *mt9m111,
- struct v4l2_rect *rect)
+static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
+ struct v4l2_rect rect = a->c;
+ struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+ int width, height;
+ int ret;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
/* Bayer format - even size lengths */
- rect->width = ALIGN(rect->width, 2);
- rect->height = ALIGN(rect->height, 2);
+ rect.width = ALIGN(rect.width, 2);
+ rect.height = ALIGN(rect.height, 2);
/* Let the user play with the starting pixel */
}
/* FIXME: the datasheet doesn't specify minimum sizes */
- soc_camera_limit_side(&rect->left, &rect->width,
+ soc_camera_limit_side(&rect.left, &rect.width,
MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH);
- soc_camera_limit_side(&rect->top, &rect->height,
+ soc_camera_limit_side(&rect.top, &rect.height,
MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
- return mt9m111_setup_rect(mt9m111, rect);
-}
-
-static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- struct v4l2_rect rect = a->c;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
- int ret;
+ width = min(mt9m111->width, rect.width);
+ height = min(mt9m111->height, rect.height);
- dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
- __func__, rect.left, rect.top, rect.width, rect.height);
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- ret = mt9m111_make_rect(mt9m111, &rect);
- if (!ret)
+ ret = mt9m111_setup_geometry(mt9m111, &rect, width, height, mt9m111->fmt->code);
+ if (!ret) {
mt9m111->rect = rect;
+ mt9m111->width = width;
+ mt9m111->height = height;
+ }
+
return ret;
}
@@ -434,8 +453,8 @@ static int mt9m111_g_fmt(struct v4l2_subdev *sd,
{
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
- mf->width = mt9m111->rect.width;
- mf->height = mt9m111->rect.height;
+ mf->width = mt9m111->width;
+ mf->height = mt9m111->height;
mf->code = mt9m111->fmt->code;
mf->colorspace = mt9m111->fmt->colorspace;
mf->field = V4L2_FIELD_NONE;
@@ -504,46 +523,11 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
return -EINVAL;
}
- ret = reg_mask(OUTPUT_FORMAT_CTRL2_A, data_outfmt2,
- mask_outfmt2);
+ ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2,
+ data_outfmt2, mask_outfmt2);
if (!ret)
- ret = reg_mask(OUTPUT_FORMAT_CTRL2_B, data_outfmt2,
- mask_outfmt2);
-
- return ret;
-}
-
-static int mt9m111_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- const struct mt9m111_datafmt *fmt;
- struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
- struct v4l2_rect rect = {
- .left = mt9m111->rect.left,
- .top = mt9m111->rect.top,
- .width = mf->width,
- .height = mf->height,
- };
- int ret;
-
- fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts,
- ARRAY_SIZE(mt9m111_colour_fmts));
- if (!fmt)
- return -EINVAL;
-
- dev_dbg(&client->dev,
- "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__,
- mf->code, rect.left, rect.top, rect.width, rect.height);
-
- ret = mt9m111_make_rect(mt9m111, &rect);
- if (!ret)
- ret = mt9m111_set_pixfmt(mt9m111, mf->code);
- if (!ret) {
- mt9m111->rect = rect;
- mt9m111->fmt = fmt;
- mf->colorspace = fmt->colorspace;
- }
+ ret = mt9m111_reg_mask(client, context_b.output_fmt_ctrl2,
+ data_outfmt2, mask_outfmt2);
return ret;
}
@@ -551,42 +535,71 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
static int mt9m111_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
const struct mt9m111_datafmt *fmt;
- bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
-
- fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts,
- ARRAY_SIZE(mt9m111_colour_fmts));
- if (!fmt) {
- fmt = mt9m111->fmt;
- mf->code = fmt->code;
- }
+ struct v4l2_rect *rect = &mt9m111->rect;
+ bool bayer;
+
+ fmt = mt9m111_find_datafmt(mt9m111, mf->code);
+
+ bayer = fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
+ fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
/*
* With Bayer format enforce even side lengths, but let the user play
* with the starting pixel
*/
+ if (bayer) {
+ rect->width = ALIGN(rect->width, 2);
+ rect->height = ALIGN(rect->height, 2);
+ }
- if (mf->height > MT9M111_MAX_HEIGHT)
- mf->height = MT9M111_MAX_HEIGHT;
- else if (mf->height < 2)
- mf->height = 2;
- else if (bayer)
- mf->height = ALIGN(mf->height, 2);
+ if (fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+ /* IFP bypass mode, no scaling */
+ mf->width = rect->width;
+ mf->height = rect->height;
+ } else {
+ /* No upscaling */
+ if (mf->width > rect->width)
+ mf->width = rect->width;
+ if (mf->height > rect->height)
+ mf->height = rect->height;
+ }
- if (mf->width > MT9M111_MAX_WIDTH)
- mf->width = MT9M111_MAX_WIDTH;
- else if (mf->width < 2)
- mf->width = 2;
- else if (bayer)
- mf->width = ALIGN(mf->width, 2);
+ dev_dbg(&client->dev, "%s(): %ux%u, code=%x\n", __func__,
+ mf->width, mf->height, fmt->code);
+ mf->code = fmt->code;
mf->colorspace = fmt->colorspace;
return 0;
}
+static int mt9m111_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ const struct mt9m111_datafmt *fmt;
+ struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+ struct v4l2_rect *rect = &mt9m111->rect;
+ int ret;
+
+ mt9m111_try_fmt(sd, mf);
+ fmt = mt9m111_find_datafmt(mt9m111, mf->code);
+ /* try_fmt() guarantees fmt != NULL && fmt->code == mf->code */
+
+ ret = mt9m111_setup_geometry(mt9m111, rect, mf->width, mf->height, mf->code);
+ if (!ret)
+ ret = mt9m111_set_pixfmt(mt9m111, mf->code);
+ if (!ret) {
+ mt9m111->width = mf->width;
+ mt9m111->height = mf->height;
+ mt9m111->fmt = fmt;
+ }
+
+ return ret;
+}
+
static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
@@ -650,17 +663,10 @@ static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
int ret;
- if (mt9m111->context == HIGHPOWER) {
- if (flip)
- ret = reg_set(READ_MODE_B, mask);
- else
- ret = reg_clear(READ_MODE_B, mask);
- } else {
- if (flip)
- ret = reg_set(READ_MODE_A, mask);
- else
- ret = reg_clear(READ_MODE_A, mask);
- }
+ if (flip)
+ ret = mt9m111_reg_set(client, mt9m111->ctx->read_mode, mask);
+ else
+ ret = mt9m111_reg_clear(client, mt9m111->ctx->read_mode, mask);
return ret;
}
@@ -738,30 +744,39 @@ static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
static int mt9m111_suspend(struct mt9m111 *mt9m111)
{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+ int ret;
+
v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111));
- return 0;
+ ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
+ if (!ret)
+ ret = reg_set(RESET, MT9M111_RESET_RESET_SOC |
+ MT9M111_RESET_OUTPUT_DISABLE |
+ MT9M111_RESET_ANALOG_STANDBY);
+ if (!ret)
+ ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
+
+ return ret;
}
static void mt9m111_restore_state(struct mt9m111 *mt9m111)
{
- mt9m111_set_context(mt9m111, mt9m111->context);
+ mt9m111_set_context(mt9m111, mt9m111->ctx);
mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
- mt9m111_setup_rect(mt9m111, &mt9m111->rect);
+ mt9m111_setup_geometry(mt9m111, &mt9m111->rect,
+ mt9m111->width, mt9m111->height, mt9m111->fmt->code);
v4l2_ctrl_handler_setup(&mt9m111->hdl);
}
static int mt9m111_resume(struct mt9m111 *mt9m111)
{
- int ret = 0;
+ int ret = mt9m111_enable(mt9m111);
+ if (!ret)
+ ret = mt9m111_reset(mt9m111);
+ if (!ret)
+ mt9m111_restore_state(mt9m111);
- if (mt9m111->powered) {
- ret = mt9m111_enable(mt9m111);
- if (!ret)
- ret = mt9m111_reset(mt9m111);
- if (!ret)
- mt9m111_restore_state(mt9m111);
- }
return ret;
}
@@ -770,12 +785,13 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
int ret;
- mt9m111->context = HIGHPOWER;
+ /* Default HIGHPOWER context */
+ mt9m111->ctx = &context_b;
ret = mt9m111_enable(mt9m111);
if (!ret)
ret = mt9m111_reset(mt9m111);
if (!ret)
- ret = mt9m111_set_context(mt9m111, mt9m111->context);
+ ret = mt9m111_set_context(mt9m111, mt9m111->ctx);
if (ret)
dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
return ret;
@@ -992,18 +1008,7 @@ static struct i2c_driver mt9m111_i2c_driver = {
.id_table = mt9m111_id,
};
-static int __init mt9m111_mod_init(void)
-{
- return i2c_add_driver(&mt9m111_i2c_driver);
-}
-
-static void __exit mt9m111_mod_exit(void)
-{
- i2c_del_driver(&mt9m111_i2c_driver);
-}
-
-module_init(mt9m111_mod_init);
-module_exit(mt9m111_mod_exit);
+module_i2c_driver(mt9m111_i2c_driver);
MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver");
MODULE_AUTHOR("Robert Jarzmik");
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
index 73c068993f05..c81eaf4fbe01 100644
--- a/drivers/media/video/mt9p031.c
+++ b/drivers/media/video/mt9p031.c
@@ -19,7 +19,6 @@
#include <linux/log2.h>
#include <linux/pm.h>
#include <linux/slab.h>
-#include <media/v4l2-subdev.h>
#include <linux/videodev2.h>
#include <media/mt9p031.h>
@@ -28,6 +27,8 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
+#include "aptina-pll.h"
+
#define MT9P031_PIXEL_ARRAY_WIDTH 2752
#define MT9P031_PIXEL_ARRAY_HEIGHT 2004
@@ -98,14 +99,6 @@
#define MT9P031_TEST_PATTERN_RED 0xa2
#define MT9P031_TEST_PATTERN_BLUE 0xa3
-struct mt9p031_pll_divs {
- u32 ext_freq;
- u32 target_freq;
- u8 m;
- u8 n;
- u8 p1;
-};
-
struct mt9p031 {
struct v4l2_subdev subdev;
struct media_pad pad;
@@ -115,10 +108,8 @@ struct mt9p031 {
struct mt9p031_platform_data *pdata;
struct mutex power_lock; /* lock to protect power_count */
int power_count;
- u16 xskip;
- u16 yskip;
- const struct mt9p031_pll_divs *pll;
+ struct aptina_pll pll;
/* Registers cache */
u16 output_control;
@@ -132,13 +123,12 @@ static struct mt9p031 *to_mt9p031(struct v4l2_subdev *sd)
static int mt9p031_read(struct i2c_client *client, u8 reg)
{
- s32 data = i2c_smbus_read_word_data(client, reg);
- return data < 0 ? data : be16_to_cpu(data);
+ return i2c_smbus_read_word_swapped(client, reg);
}
static int mt9p031_write(struct i2c_client *client, u8 reg, u16 data)
{
- return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+ return i2c_smbus_write_word_swapped(client, reg, data);
}
static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear,
@@ -187,33 +177,31 @@ static int mt9p031_reset(struct mt9p031 *mt9p031)
0);
}
-/*
- * This static table uses ext_freq and vdd_io values to select suitable
- * PLL dividers m, n and p1 which have been calculated as specifiec in p36
- * of Aptina's mt9p031 datasheet. New values should be added here.
- */
-static const struct mt9p031_pll_divs mt9p031_divs[] = {
- /* ext_freq target_freq m n p1 */
- {21000000, 48000000, 26, 2, 6}
-};
-
-static int mt9p031_pll_get_divs(struct mt9p031 *mt9p031)
+static int mt9p031_pll_setup(struct mt9p031 *mt9p031)
{
+ static const struct aptina_pll_limits limits = {
+ .ext_clock_min = 6000000,
+ .ext_clock_max = 27000000,
+ .int_clock_min = 2000000,
+ .int_clock_max = 13500000,
+ .out_clock_min = 180000000,
+ .out_clock_max = 360000000,
+ .pix_clock_max = 96000000,
+ .n_min = 1,
+ .n_max = 64,
+ .m_min = 16,
+ .m_max = 255,
+ .p1_min = 1,
+ .p1_max = 128,
+ };
+
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
- int i;
+ struct mt9p031_platform_data *pdata = mt9p031->pdata;
- for (i = 0; i < ARRAY_SIZE(mt9p031_divs); i++) {
- if (mt9p031_divs[i].ext_freq == mt9p031->pdata->ext_freq &&
- mt9p031_divs[i].target_freq == mt9p031->pdata->target_freq) {
- mt9p031->pll = &mt9p031_divs[i];
- return 0;
- }
- }
+ mt9p031->pll.ext_clock = pdata->ext_freq;
+ mt9p031->pll.pix_clock = pdata->target_freq;
- dev_err(&client->dev, "Couldn't find PLL dividers for ext_freq = %d, "
- "target_freq = %d\n", mt9p031->pdata->ext_freq,
- mt9p031->pdata->target_freq);
- return -EINVAL;
+ return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
}
static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
@@ -227,11 +215,11 @@ static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
return ret;
ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1,
- (mt9p031->pll->m << 8) | (mt9p031->pll->n - 1));
+ (mt9p031->pll.m << 8) | (mt9p031->pll.n - 1));
if (ret < 0)
return ret;
- ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll->p1 - 1);
+ ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll.p1 - 1);
if (ret < 0)
return ret;
@@ -786,8 +774,6 @@ static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
format->field = V4L2_FIELD_NONE;
format->colorspace = V4L2_COLORSPACE_SRGB;
- mt9p031->xskip = 1;
- mt9p031->yskip = 1;
return mt9p031_set_power(subdev, 1);
}
@@ -906,7 +892,7 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->format.field = V4L2_FIELD_NONE;
mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
- ret = mt9p031_pll_get_divs(mt9p031);
+ ret = mt9p031_pll_setup(mt9p031);
done:
if (ret < 0) {
@@ -946,18 +932,7 @@ static struct i2c_driver mt9p031_i2c_driver = {
.id_table = mt9p031_id,
};
-static int __init mt9p031_mod_init(void)
-{
- return i2c_add_driver(&mt9p031_i2c_driver);
-}
-
-static void __exit mt9p031_mod_exit(void)
-{
- i2c_del_driver(&mt9p031_i2c_driver);
-}
-
-module_init(mt9p031_mod_init);
-module_exit(mt9p031_mod_exit);
+module_i2c_driver(mt9p031_i2c_driver);
MODULE_DESCRIPTION("Aptina MT9P031 Camera driver");
MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
diff --git a/drivers/media/video/mt9t001.c b/drivers/media/video/mt9t001.c
index 08074b8a2736..49ca3cbfc6f1 100644
--- a/drivers/media/video/mt9t001.c
+++ b/drivers/media/video/mt9t001.c
@@ -133,13 +133,12 @@ static inline struct mt9t001 *to_mt9t001(struct v4l2_subdev *sd)
static int mt9t001_read(struct i2c_client *client, u8 reg)
{
- s32 data = i2c_smbus_read_word_data(client, reg);
- return data < 0 ? data : be16_to_cpu(data);
+ return i2c_smbus_read_word_swapped(client, reg);
}
static int mt9t001_write(struct i2c_client *client, u8 reg, u16 data)
{
- return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+ return i2c_smbus_write_word_swapped(client, reg, data);
}
static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear,
@@ -818,18 +817,7 @@ static struct i2c_driver mt9t001_driver = {
.id_table = mt9t001_id,
};
-static int __init mt9t001_init(void)
-{
- return i2c_add_driver(&mt9t001_driver);
-}
-
-static void __exit mt9t001_exit(void)
-{
- i2c_del_driver(&mt9t001_driver);
-}
-
-module_init(mt9t001_init);
-module_exit(mt9t001_exit);
+module_i2c_driver(mt9t001_driver);
MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver");
MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index 0e78477452ff..1415074138a5 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -90,14 +90,13 @@ static struct mt9t031 *to_mt9t031(const struct i2c_client *client)
static int reg_read(struct i2c_client *client, const u8 reg)
{
- s32 data = i2c_smbus_read_word_data(client, reg);
- return data < 0 ? data : swab16(data);
+ return i2c_smbus_read_word_swapped(client, reg);
}
static int reg_write(struct i2c_client *client, const u8 reg,
const u16 data)
{
- return i2c_smbus_write_word_data(client, reg, swab16(data));
+ return i2c_smbus_write_word_swapped(client, reg, data);
}
static int reg_set(struct i2c_client *client, const u8 reg,
@@ -851,18 +850,7 @@ static struct i2c_driver mt9t031_i2c_driver = {
.id_table = mt9t031_id,
};
-static int __init mt9t031_mod_init(void)
-{
- return i2c_add_driver(&mt9t031_i2c_driver);
-}
-
-static void __exit mt9t031_mod_exit(void)
-{
- i2c_del_driver(&mt9t031_i2c_driver);
-}
-
-module_init(mt9t031_mod_init);
-module_exit(mt9t031_mod_exit);
+module_i2c_driver(mt9t031_i2c_driver);
MODULE_DESCRIPTION("Micron MT9T031 Camera driver");
MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index 7b34b11daf24..8d1445f12708 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -1117,21 +1117,7 @@ static struct i2c_driver mt9t112_i2c_driver = {
.id_table = mt9t112_id,
};
-/************************************************************************
- module function
-************************************************************************/
-static int __init mt9t112_module_init(void)
-{
- return i2c_add_driver(&mt9t112_i2c_driver);
-}
-
-static void __exit mt9t112_module_exit(void)
-{
- i2c_del_driver(&mt9t112_i2c_driver);
-}
-
-module_init(mt9t112_module_init);
-module_exit(mt9t112_module_exit);
+module_i2c_driver(mt9t112_i2c_driver);
MODULE_DESCRIPTION("SoC Camera driver for mt9t112");
MODULE_AUTHOR("Kuninori Morimoto");
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index db74dd27c722..6bf01ad62765 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -709,15 +709,4 @@ static struct i2c_driver mt9v011_driver = {
.id_table = mt9v011_id,
};
-static __init int init_mt9v011(void)
-{
- return i2c_add_driver(&mt9v011_driver);
-}
-
-static __exit void exit_mt9v011(void)
-{
- i2c_del_driver(&mt9v011_driver);
-}
-
-module_init(init_mt9v011);
-module_exit(exit_mt9v011);
+module_i2c_driver(mt9v011_driver);
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 690ee0d42eeb..bf63417adb8f 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -130,14 +130,13 @@ static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
static int reg_read(struct i2c_client *client, const u8 reg)
{
- s32 data = i2c_smbus_read_word_data(client, reg);
- return data < 0 ? data : swab16(data);
+ return i2c_smbus_read_word_swapped(client, reg);
}
static int reg_write(struct i2c_client *client, const u8 reg,
const u16 data)
{
- return i2c_smbus_write_word_data(client, reg, swab16(data));
+ return i2c_smbus_write_word_swapped(client, reg, data);
}
static int reg_set(struct i2c_client *client, const u8 reg,
@@ -873,18 +872,7 @@ static struct i2c_driver mt9v022_i2c_driver = {
.id_table = mt9v022_id,
};
-static int __init mt9v022_mod_init(void)
-{
- return i2c_add_driver(&mt9v022_i2c_driver);
-}
-
-static void __exit mt9v022_mod_exit(void)
-{
- i2c_del_driver(&mt9v022_i2c_driver);
-}
-
-module_init(mt9v022_mod_init);
-module_exit(mt9v022_mod_exit);
+module_i2c_driver(mt9v022_i2c_driver);
MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c
index f080c162123f..75e253a343c5 100644
--- a/drivers/media/video/mt9v032.c
+++ b/drivers/media/video/mt9v032.c
@@ -139,10 +139,10 @@ static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
static int mt9v032_read(struct i2c_client *client, const u8 reg)
{
- s32 data = i2c_smbus_read_word_data(client, reg);
+ s32 data = i2c_smbus_read_word_swapped(client, reg);
dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
- swab16(data), reg);
- return data < 0 ? data : swab16(data);
+ data, reg);
+ return data;
}
static int mt9v032_write(struct i2c_client *client, const u8 reg,
@@ -150,7 +150,7 @@ static int mt9v032_write(struct i2c_client *client, const u8 reg,
{
dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
data, reg);
- return i2c_smbus_write_word_data(client, reg, swab16(data));
+ return i2c_smbus_write_word_swapped(client, reg, data);
}
static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
@@ -756,18 +756,7 @@ static struct i2c_driver mt9v032_driver = {
.id_table = mt9v032_id,
};
-static int __init mt9v032_init(void)
-{
- return i2c_add_driver(&mt9v032_driver);
-}
-
-static void __exit mt9v032_exit(void)
-{
- i2c_del_driver(&mt9v032_driver);
-}
-
-module_init(mt9v032_init);
-module_exit(mt9v032_exit);
+module_i2c_driver(mt9v032_driver);
MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index 18e94c7d2be8..055d11ddb038 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -487,7 +487,7 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd,
return v4l2_subdev_call(sd, video, s_crop, a);
}
-static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static int mx1_camera_set_bus_param(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
index a803d9ea8fd6..18afaeeadb7b 100644
--- a/drivers/media/video/mx2_camera.c
+++ b/drivers/media/video/mx2_camera.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2008, Sascha Hauer, Pengutronix
* Copyright (C) 2010, Baruch Siach, Orex Computed Radiography
+ * Copyright (C) 2012, Javier Martin, Vista Silicon S.L.
*
* 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
@@ -18,6 +19,7 @@
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/fs.h>
+#include <linux/gcd.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -30,17 +32,14 @@
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
-#include <media/videobuf-core.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
#include <linux/videodev2.h>
#include <mach/mx2_cam.h>
-#ifdef CONFIG_MACH_MX27
-#include <mach/dma-mx1-mx2.h>
-#endif
#include <mach/hardware.h>
#include <asm/dma.h>
@@ -206,10 +205,66 @@
#define PRP_INTR_LBOVF (1 << 7)
#define PRP_INTR_CH2OVF (1 << 8)
-#define mx27_camera_emma(pcdev) (cpu_is_mx27() && pcdev->use_emma)
+/* Resizing registers */
+#define PRP_RZ_VALID_TBL_LEN(x) ((x) << 24)
+#define PRP_RZ_VALID_BILINEAR (1 << 31)
#define MAX_VIDEO_MEM 16
+#define RESIZE_NUM_MIN 1
+#define RESIZE_NUM_MAX 20
+#define BC_COEF 3
+#define SZ_COEF (1 << BC_COEF)
+
+#define RESIZE_DIR_H 0
+#define RESIZE_DIR_V 1
+
+#define RESIZE_ALGO_BILINEAR 0
+#define RESIZE_ALGO_AVERAGING 1
+
+struct mx2_prp_cfg {
+ int channel;
+ u32 in_fmt;
+ u32 out_fmt;
+ u32 src_pixel;
+ u32 ch1_pixel;
+ u32 irq_flags;
+};
+
+/* prp resizing parameters */
+struct emma_prp_resize {
+ int algo; /* type of algorithm used */
+ int len; /* number of coefficients */
+ unsigned char s[RESIZE_NUM_MAX]; /* table of coefficients */
+};
+
+/* prp configuration for a client-host fmt pair */
+struct mx2_fmt_cfg {
+ enum v4l2_mbus_pixelcode in_fmt;
+ u32 out_fmt;
+ struct mx2_prp_cfg cfg;
+};
+
+enum mx2_buffer_state {
+ MX2_STATE_QUEUED,
+ MX2_STATE_ACTIVE,
+ MX2_STATE_DONE,
+};
+
+struct mx2_buf_internal {
+ struct list_head queue;
+ int bufnum;
+ bool discard;
+};
+
+/* buffer for one video frame */
+struct mx2_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct vb2_buffer vb;
+ enum mx2_buffer_state state;
+ struct mx2_buf_internal internal;
+};
+
struct mx2_camera_dev {
struct device *dev;
struct soc_camera_host soc_host;
@@ -226,6 +281,7 @@ struct mx2_camera_dev {
struct list_head capture;
struct list_head active_bufs;
+ struct list_head discard;
spinlock_t lock;
@@ -234,32 +290,107 @@ struct mx2_camera_dev {
struct mx2_buffer *fb1_active;
struct mx2_buffer *fb2_active;
- int use_emma;
-
u32 csicr1;
+ struct mx2_buf_internal buf_discard[2];
void *discard_buffer;
dma_addr_t discard_buffer_dma;
size_t discard_size;
+ struct mx2_fmt_cfg *emma_prp;
+ struct emma_prp_resize resizing[2];
+ unsigned int s_width, s_height;
+ u32 frame_count;
+ struct vb2_alloc_ctx *alloc_ctx;
};
-/* buffer for one video frame */
-struct mx2_buffer {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
+static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf)
+{
+ return container_of(int_buf, struct mx2_buffer, internal);
+}
- enum v4l2_mbus_pixelcode code;
+static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
+ /*
+ * This is a generic configuration which is valid for most
+ * prp input-output format combinations.
+ * We set the incomming and outgoing pixelformat to a
+ * 16 Bit wide format and adjust the bytesperline
+ * accordingly. With this configuration the inputdata
+ * will not be changed by the emma and could be any type
+ * of 16 Bit Pixelformat.
+ */
+ {
+ .in_fmt = 0,
+ .out_fmt = 0,
+ .cfg = {
+ .channel = 1,
+ .in_fmt = PRP_CNTL_DATA_IN_RGB16,
+ .out_fmt = PRP_CNTL_CH1_OUT_RGB16,
+ .src_pixel = 0x2ca00565, /* RGB565 */
+ .ch1_pixel = 0x2ca00565, /* RGB565 */
+ .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR |
+ PRP_INTR_CH1FC | PRP_INTR_LBOVF,
+ }
+ },
+ {
+ .in_fmt = V4L2_MBUS_FMT_YUYV8_2X8,
+ .out_fmt = V4L2_PIX_FMT_YUV420,
+ .cfg = {
+ .channel = 2,
+ .in_fmt = PRP_CNTL_DATA_IN_YUV422,
+ .out_fmt = PRP_CNTL_CH2_OUT_YUV420,
+ .src_pixel = 0x22000888, /* YUV422 (YUYV) */
+ .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR |
+ PRP_INTR_CH2FC | PRP_INTR_LBOVF |
+ PRP_INTR_CH2OVF,
+ }
+ },
+};
- int bufnum;
+static struct mx2_fmt_cfg *mx27_emma_prp_get_format(
+ enum v4l2_mbus_pixelcode in_fmt,
+ u32 out_fmt)
+{
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(mx27_emma_prp_table); i++)
+ if ((mx27_emma_prp_table[i].in_fmt == in_fmt) &&
+ (mx27_emma_prp_table[i].out_fmt == out_fmt)) {
+ return &mx27_emma_prp_table[i];
+ }
+ /* If no match return the most generic configuration */
+ return &mx27_emma_prp_table[0];
};
+static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev,
+ unsigned long phys, int bufnum)
+{
+ struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+
+ if (prp->cfg.channel == 1) {
+ writel(phys, pcdev->base_emma +
+ PRP_DEST_RGB1_PTR + 4 * bufnum);
+ } else {
+ writel(phys, pcdev->base_emma +
+ PRP_DEST_Y_PTR - 0x14 * bufnum);
+ if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
+ u32 imgsize = pcdev->icd->user_height *
+ pcdev->icd->user_width;
+
+ writel(phys + imgsize, pcdev->base_emma +
+ PRP_DEST_CB_PTR - 0x14 * bufnum);
+ writel(phys + ((5 * imgsize) / 4), pcdev->base_emma +
+ PRP_DEST_CR_PTR - 0x14 * bufnum);
+ }
+ }
+}
+
static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
{
unsigned long flags;
clk_disable(pcdev->clk_csi);
writel(0, pcdev->base_csi + CSICR1);
- if (mx27_camera_emma(pcdev)) {
+ if (cpu_is_mx27()) {
writel(0, pcdev->base_emma + PRP_CNTL);
} else if (cpu_is_mx25()) {
spin_lock_irqsave(&pcdev->lock, flags);
@@ -291,7 +422,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
csicr1 = CSICR1_MCLKEN;
- if (mx27_camera_emma(pcdev)) {
+ if (cpu_is_mx27()) {
csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
CSICR1_RXFF_LEVEL(0);
} else if (cpu_is_mx27())
@@ -301,6 +432,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
pcdev->icd = icd;
+ pcdev->frame_count = 0;
dev_info(icd->parent, "Camera driver attached to camera %d\n",
icd->devnum);
@@ -320,56 +452,13 @@ static void mx2_camera_remove_device(struct soc_camera_device *icd)
mx2_camera_deactivate(pcdev);
- if (pcdev->discard_buffer) {
- dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size,
- pcdev->discard_buffer,
- pcdev->discard_buffer_dma);
- pcdev->discard_buffer = NULL;
- }
-
pcdev->icd = NULL;
}
-#ifdef CONFIG_MACH_MX27
-static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev)
-{
- u32 tmp;
-
- imx_dma_enable(pcdev->dma);
-
- tmp = readl(pcdev->base_csi + CSICR1);
- tmp |= CSICR1_RF_OR_INTEN;
- writel(tmp, pcdev->base_csi + CSICR1);
-}
-
-static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
-{
- struct mx2_camera_dev *pcdev = data;
- u32 status = readl(pcdev->base_csi + CSISR);
-
- if (status & CSISR_SOF_INT && pcdev->active) {
- u32 tmp;
-
- tmp = readl(pcdev->base_csi + CSICR1);
- writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1);
- mx27_camera_dma_enable(pcdev);
- }
-
- writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR);
-
- return IRQ_HANDLED;
-}
-#else
-static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
-{
- return IRQ_NONE;
-}
-#endif /* CONFIG_MACH_MX27 */
-
static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
int state)
{
- struct videobuf_buffer *vb;
+ struct vb2_buffer *vb;
struct mx2_buffer *buf;
struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
&pcdev->fb2_active;
@@ -382,25 +471,24 @@ static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
goto out;
vb = &(*fb_active)->vb;
- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
-
- vb->state = state;
- do_gettimeofday(&vb->ts);
- vb->field_count++;
+ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
- wake_up(&vb->done);
+ do_gettimeofday(&vb->v4l2_buf.timestamp);
+ vb->v4l2_buf.sequence++;
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
if (list_empty(&pcdev->capture)) {
buf = NULL;
writel(0, pcdev->base_csi + fb_reg);
} else {
- buf = list_entry(pcdev->capture.next, struct mx2_buffer,
- vb.queue);
+ buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+ internal.queue);
vb = &buf->vb;
- list_del(&vb->queue);
- vb->state = VIDEOBUF_ACTIVE;
- writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg);
+ list_del(&buf->internal.queue);
+ buf->state = MX2_STATE_ACTIVE;
+ writel(vb2_dma_contig_plane_dma_addr(vb, 0),
+ pcdev->base_csi + fb_reg);
}
*fb_active = buf;
@@ -415,9 +503,9 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
u32 status = readl(pcdev->base_csi + CSISR);
if (status & CSISR_DMA_TSF_FB1_INT)
- mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE);
+ mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE);
else if (status & CSISR_DMA_TSF_FB2_INT)
- mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE);
+ mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE);
/* FIXME: handle CSISR_RFF_OR_INT */
@@ -429,59 +517,50 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
/*
* Videobuf operations
*/
-static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
+static int mx2_videobuf_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *count, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
- dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
+ dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]);
+
+ /* TODO: support for VIDIOC_CREATE_BUFS not ready */
+ if (fmt != NULL)
+ return -ENOTTY;
if (bytes_per_line < 0)
return bytes_per_line;
- *size = bytes_per_line * icd->user_height;
+ alloc_ctxs[0] = pcdev->alloc_ctx;
+
+ sizes[0] = bytes_per_line * icd->user_height;
if (0 == *count)
*count = 32;
- if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
- *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
-
- return 0;
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
-{
- struct soc_camera_device *icd = vq->priv_data;
- struct videobuf_buffer *vb = &buf->vb;
+ if (!*num_planes &&
+ sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
+ *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0];
- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
+ *num_planes = 1;
- /*
- * This waits until this buffer is out of danger, i.e., until it is no
- * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE
- */
- videobuf_waiton(vq, vb, 0, 0);
-
- videobuf_dma_contig_free(vq, vb);
- dev_dbg(icd->parent, "%s freed\n", __func__);
-
- vb->state = VIDEOBUF_NEEDS_INIT;
+ return 0;
}
-static int mx2_videobuf_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb, enum v4l2_field field)
+static int mx2_videobuf_prepare(struct vb2_buffer *vb)
{
- struct soc_camera_device *icd = vq->priv_data;
- struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
int ret = 0;
- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
+ dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
if (bytes_per_line < 0)
return bytes_per_line;
@@ -491,99 +570,58 @@ static int mx2_videobuf_prepare(struct videobuf_queue *vq,
* This can be useful if you want to see if we actually fill
* the buffer with something
*/
- memset((void *)vb->baddr, 0xaa, vb->bsize);
+ memset((void *)vb2_plane_vaddr(vb, 0),
+ 0xaa, vb2_get_plane_payload(vb, 0));
#endif
- if (buf->code != icd->current_fmt->code ||
- vb->width != icd->user_width ||
- vb->height != icd->user_height ||
- vb->field != field) {
- buf->code = icd->current_fmt->code;
- vb->width = icd->user_width;
- vb->height = icd->user_height;
- vb->field = field;
- vb->state = VIDEOBUF_NEEDS_INIT;
- }
-
- vb->size = bytes_per_line * vb->height;
- if (vb->baddr && vb->bsize < vb->size) {
+ vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height);
+ if (vb2_plane_vaddr(vb, 0) &&
+ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
ret = -EINVAL;
goto out;
}
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- ret = videobuf_iolock(vq, vb, NULL);
- if (ret)
- goto fail;
-
- vb->state = VIDEOBUF_PREPARED;
- }
-
return 0;
-fail:
- free_buffer(vq, buf);
out:
return ret;
}
-static void mx2_videobuf_queue(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
+static void mx2_videobuf_queue(struct vb2_buffer *vb)
{
- struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
struct soc_camera_host *ici =
to_soc_camera_host(icd->parent);
struct mx2_camera_dev *pcdev = ici->priv;
struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
unsigned long flags;
- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
+ dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
spin_lock_irqsave(&pcdev->lock, flags);
- vb->state = VIDEOBUF_QUEUED;
- list_add_tail(&vb->queue, &pcdev->capture);
+ buf->state = MX2_STATE_QUEUED;
+ list_add_tail(&buf->internal.queue, &pcdev->capture);
- if (mx27_camera_emma(pcdev)) {
- goto out;
-#ifdef CONFIG_MACH_MX27
- } else if (cpu_is_mx27()) {
- int ret;
-
- if (pcdev->active == NULL) {
- ret = imx_dma_setup_single(pcdev->dma,
- videobuf_to_dma_contig(vb), vb->size,
- (u32)pcdev->base_dma + 0x10,
- DMA_MODE_READ);
- if (ret) {
- vb->state = VIDEOBUF_ERROR;
- wake_up(&vb->done);
- goto out;
- }
-
- vb->state = VIDEOBUF_ACTIVE;
- pcdev->active = buf;
- }
-#endif
- } else { /* cpu_is_mx25() */
+ if (cpu_is_mx25()) {
u32 csicr3, dma_inten = 0;
if (pcdev->fb1_active == NULL) {
- writel(videobuf_to_dma_contig(vb),
+ writel(vb2_dma_contig_plane_dma_addr(vb, 0),
pcdev->base_csi + CSIDMASA_FB1);
pcdev->fb1_active = buf;
dma_inten = CSICR1_FB1_DMA_INTEN;
} else if (pcdev->fb2_active == NULL) {
- writel(videobuf_to_dma_contig(vb),
+ writel(vb2_dma_contig_plane_dma_addr(vb, 0),
pcdev->base_csi + CSIDMASA_FB2);
pcdev->fb2_active = buf;
dma_inten = CSICR1_FB2_DMA_INTEN;
}
if (dma_inten) {
- list_del(&vb->queue);
- vb->state = VIDEOBUF_ACTIVE;
+ list_del(&buf->internal.queue);
+ buf->state = MX2_STATE_ACTIVE;
csicr3 = readl(pcdev->base_csi + CSICR3);
@@ -602,36 +640,31 @@ static void mx2_videobuf_queue(struct videobuf_queue *vq,
}
}
-out:
spin_unlock_irqrestore(&pcdev->lock, flags);
}
-static void mx2_videobuf_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
+static void mx2_videobuf_release(struct vb2_buffer *vb)
{
- struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx2_camera_dev *pcdev = ici->priv;
struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
unsigned long flags;
#ifdef DEBUG
- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
+ dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
- switch (vb->state) {
- case VIDEOBUF_ACTIVE:
+ switch (buf->state) {
+ case MX2_STATE_ACTIVE:
dev_info(icd->parent, "%s (active)\n", __func__);
break;
- case VIDEOBUF_QUEUED:
+ case MX2_STATE_QUEUED:
dev_info(icd->parent, "%s (queued)\n", __func__);
break;
- case VIDEOBUF_PREPARED:
- dev_info(icd->parent, "%s (prepared)\n", __func__);
- break;
default:
dev_info(icd->parent, "%s (unknown) %d\n", __func__,
- vb->state);
+ buf->state);
break;
}
#endif
@@ -645,11 +678,9 @@ static void mx2_videobuf_release(struct videobuf_queue *vq,
* state. This requires a specific handling for each of the these DMA
* types.
*/
+
spin_lock_irqsave(&pcdev->lock, flags);
- if (vb->state == VIDEOBUF_QUEUED) {
- list_del(&vb->queue);
- vb->state = VIDEOBUF_ERROR;
- } else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) {
+ if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) {
if (pcdev->fb1_active == buf) {
pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
writel(0, pcdev->base_csi + CSIDMASA_FB1);
@@ -660,30 +691,260 @@ static void mx2_videobuf_release(struct videobuf_queue *vq,
pcdev->fb2_active = NULL;
}
writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
- vb->state = VIDEOBUF_ERROR;
}
spin_unlock_irqrestore(&pcdev->lock, flags);
+}
- free_buffer(vq, buf);
+static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
+ int bytesperline)
+{
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
+ struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+
+ writel((pcdev->s_width << 16) | pcdev->s_height,
+ pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+ writel(prp->cfg.src_pixel,
+ pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
+ if (prp->cfg.channel == 1) {
+ writel((icd->user_width << 16) | icd->user_height,
+ pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
+ writel(bytesperline,
+ pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
+ writel(prp->cfg.ch1_pixel,
+ pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
+ } else { /* channel 2 */
+ writel((icd->user_width << 16) | icd->user_height,
+ pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
+ }
+
+ /* Enable interrupts */
+ writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
}
-static struct videobuf_queue_ops mx2_videobuf_ops = {
- .buf_setup = mx2_videobuf_setup,
- .buf_prepare = mx2_videobuf_prepare,
- .buf_queue = mx2_videobuf_queue,
- .buf_release = mx2_videobuf_release,
-};
+static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev)
+{
+ int dir;
-static void mx2_camera_init_videobuf(struct videobuf_queue *q,
- struct soc_camera_device *icd)
+ for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
+ unsigned char *s = pcdev->resizing[dir].s;
+ int len = pcdev->resizing[dir].len;
+ unsigned int coeff[2] = {0, 0};
+ unsigned int valid = 0;
+ int i;
+
+ if (len == 0)
+ continue;
+
+ for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) {
+ int j;
+
+ j = i > 9 ? 1 : 0;
+ coeff[j] = (coeff[j] << BC_COEF) |
+ (s[i] & (SZ_COEF - 1));
+
+ if (i == 5 || i == 15)
+ coeff[j] <<= 1;
+
+ valid = (valid << 1) | (s[i] >> BC_COEF);
+ }
+
+ valid |= PRP_RZ_VALID_TBL_LEN(len);
+
+ if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR)
+ valid |= PRP_RZ_VALID_BILINEAR;
+
+ if (pcdev->emma_prp->cfg.channel == 1) {
+ if (dir == RESIZE_DIR_H) {
+ writel(coeff[0], pcdev->base_emma +
+ PRP_CH1_RZ_HORI_COEF1);
+ writel(coeff[1], pcdev->base_emma +
+ PRP_CH1_RZ_HORI_COEF2);
+ writel(valid, pcdev->base_emma +
+ PRP_CH1_RZ_HORI_VALID);
+ } else {
+ writel(coeff[0], pcdev->base_emma +
+ PRP_CH1_RZ_VERT_COEF1);
+ writel(coeff[1], pcdev->base_emma +
+ PRP_CH1_RZ_VERT_COEF2);
+ writel(valid, pcdev->base_emma +
+ PRP_CH1_RZ_VERT_VALID);
+ }
+ } else {
+ if (dir == RESIZE_DIR_H) {
+ writel(coeff[0], pcdev->base_emma +
+ PRP_CH2_RZ_HORI_COEF1);
+ writel(coeff[1], pcdev->base_emma +
+ PRP_CH2_RZ_HORI_COEF2);
+ writel(valid, pcdev->base_emma +
+ PRP_CH2_RZ_HORI_VALID);
+ } else {
+ writel(coeff[0], pcdev->base_emma +
+ PRP_CH2_RZ_VERT_COEF1);
+ writel(coeff[1], pcdev->base_emma +
+ PRP_CH2_RZ_VERT_COEF2);
+ writel(valid, pcdev->base_emma +
+ PRP_CH2_RZ_VERT_VALID);
+ }
+ }
+ }
+}
+
+static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
+ struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+ struct vb2_buffer *vb;
+ struct mx2_buffer *buf;
+ unsigned long phys;
+ int bytesperline;
+
+ if (cpu_is_mx27()) {
+ unsigned long flags;
+ if (count < 2)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+ internal.queue);
+ buf->internal.bufnum = 0;
+ vb = &buf->vb;
+ buf->state = MX2_STATE_ACTIVE;
+
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
+ list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+ buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+ internal.queue);
+ buf->internal.bufnum = 1;
+ vb = &buf->vb;
+ buf->state = MX2_STATE_ACTIVE;
+
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
+ list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+ bytesperline = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ if (bytesperline < 0)
+ return bytesperline;
+
+ /*
+ * I didn't manage to properly enable/disable the prp
+ * on a per frame basis during running transfers,
+ * thus we allocate a buffer here and use it to
+ * discard frames when no buffer is available.
+ * Feel free to work on this ;)
+ */
+ pcdev->discard_size = icd->user_height * bytesperline;
+ pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
+ pcdev->discard_size, &pcdev->discard_buffer_dma,
+ GFP_KERNEL);
+ if (!pcdev->discard_buffer)
+ return -ENOMEM;
+
+ pcdev->buf_discard[0].discard = true;
+ list_add_tail(&pcdev->buf_discard[0].queue,
+ &pcdev->discard);
+
+ pcdev->buf_discard[1].discard = true;
+ list_add_tail(&pcdev->buf_discard[1].queue,
+ &pcdev->discard);
+
+ mx2_prp_resize_commit(pcdev);
+
+ mx27_camera_emma_buf_init(icd, bytesperline);
+
+ if (prp->cfg.channel == 1) {
+ writel(PRP_CNTL_CH1EN |
+ PRP_CNTL_CSIEN |
+ prp->cfg.in_fmt |
+ prp->cfg.out_fmt |
+ PRP_CNTL_CH1_LEN |
+ PRP_CNTL_CH1BYP |
+ PRP_CNTL_CH1_TSKIP(0) |
+ PRP_CNTL_IN_TSKIP(0),
+ pcdev->base_emma + PRP_CNTL);
+ } else {
+ writel(PRP_CNTL_CH2EN |
+ PRP_CNTL_CSIEN |
+ prp->cfg.in_fmt |
+ prp->cfg.out_fmt |
+ PRP_CNTL_CH2_LEN |
+ PRP_CNTL_CH2_TSKIP(0) |
+ PRP_CNTL_IN_TSKIP(0),
+ pcdev->base_emma + PRP_CNTL);
+ }
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+ }
+
+ return 0;
+}
+
+static int mx2_stop_streaming(struct vb2_queue *q)
+{
+ struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->parent);
struct mx2_camera_dev *pcdev = ici->priv;
+ struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+ unsigned long flags;
+ void *b;
+ u32 cntl;
+
+ if (cpu_is_mx27()) {
+ spin_lock_irqsave(&pcdev->lock, flags);
- videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev,
- &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE, sizeof(struct mx2_buffer),
- icd, &icd->video_lock);
+ cntl = readl(pcdev->base_emma + PRP_CNTL);
+ if (prp->cfg.channel == 1) {
+ writel(cntl & ~PRP_CNTL_CH1EN,
+ pcdev->base_emma + PRP_CNTL);
+ } else {
+ writel(cntl & ~PRP_CNTL_CH2EN,
+ pcdev->base_emma + PRP_CNTL);
+ }
+ INIT_LIST_HEAD(&pcdev->capture);
+ INIT_LIST_HEAD(&pcdev->active_bufs);
+ INIT_LIST_HEAD(&pcdev->discard);
+
+ b = pcdev->discard_buffer;
+ pcdev->discard_buffer = NULL;
+
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+
+ dma_free_coherent(ici->v4l2_dev.dev,
+ pcdev->discard_size, b, pcdev->discard_buffer_dma);
+ }
+
+ return 0;
+}
+
+static struct vb2_ops mx2_videobuf_ops = {
+ .queue_setup = mx2_videobuf_setup,
+ .buf_prepare = mx2_videobuf_prepare,
+ .buf_queue = mx2_videobuf_queue,
+ .buf_cleanup = mx2_videobuf_release,
+ .start_streaming = mx2_start_streaming,
+ .stop_streaming = mx2_stop_streaming,
+};
+
+static int mx2_camera_init_videobuf(struct vb2_queue *q,
+ struct soc_camera_device *icd)
+{
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->drv_priv = icd;
+ q->ops = &mx2_videobuf_ops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct mx2_buffer);
+
+ return vb2_queue_init(q);
}
#define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \
@@ -713,61 +974,7 @@ static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
return -ETIMEDOUT;
}
-static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
- int bytesperline)
-{
- struct soc_camera_host *ici =
- to_soc_camera_host(icd->parent);
- struct mx2_camera_dev *pcdev = ici->priv;
-
- writel(pcdev->discard_buffer_dma,
- pcdev->base_emma + PRP_DEST_RGB1_PTR);
- writel(pcdev->discard_buffer_dma,
- pcdev->base_emma + PRP_DEST_RGB2_PTR);
-
- /*
- * We only use the EMMA engine to get rid of the broken
- * DMA Engine. No color space consversion at the moment.
- * We set the incomming and outgoing pixelformat to an
- * 16 Bit wide format and adjust the bytesperline
- * accordingly. With this configuration the inputdata
- * will not be changed by the emma and could be any type
- * of 16 Bit Pixelformat.
- */
- writel(PRP_CNTL_CH1EN |
- PRP_CNTL_CSIEN |
- PRP_CNTL_DATA_IN_RGB16 |
- PRP_CNTL_CH1_OUT_RGB16 |
- PRP_CNTL_CH1_LEN |
- PRP_CNTL_CH1BYP |
- PRP_CNTL_CH1_TSKIP(0) |
- PRP_CNTL_IN_TSKIP(0),
- pcdev->base_emma + PRP_CNTL);
-
- writel(((bytesperline >> 1) << 16) | icd->user_height,
- pcdev->base_emma + PRP_SRC_FRAME_SIZE);
- writel(((bytesperline >> 1) << 16) | icd->user_height,
- pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
- writel(bytesperline,
- pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
- writel(0x2ca00565, /* RGB565 */
- pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
- writel(0x2ca00565, /* RGB565 */
- pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
-
- /* Enable interrupts */
- writel(PRP_INTR_RDERR |
- PRP_INTR_CH1WERR |
- PRP_INTR_CH2WERR |
- PRP_INTR_CH1FC |
- PRP_INTR_CH2FC |
- PRP_INTR_LBOVF |
- PRP_INTR_CH2OVF,
- pcdev->base_emma + PRP_INTR_CNTL);
-}
-
-static int mx2_camera_set_bus_param(struct soc_camera_device *icd,
- __u32 pixfmt)
+static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -845,31 +1052,10 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd,
if (bytesperline < 0)
return bytesperline;
- if (mx27_camera_emma(pcdev)) {
+ if (cpu_is_mx27()) {
ret = mx27_camera_emma_prp_reset(pcdev);
if (ret)
return ret;
-
- if (pcdev->discard_buffer)
- dma_free_coherent(ici->v4l2_dev.dev,
- pcdev->discard_size, pcdev->discard_buffer,
- pcdev->discard_buffer_dma);
-
- /*
- * I didn't manage to properly enable/disable the prp
- * on a per frame basis during running transfers,
- * thus we allocate a buffer here and use it to
- * discard frames when no buffer is available.
- * Feel free to work on this ;)
- */
- pcdev->discard_size = icd->user_height * bytesperline;
- pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
- pcdev->discard_size, &pcdev->discard_buffer_dma,
- GFP_KERNEL);
- if (!pcdev->discard_buffer)
- return -ENOMEM;
-
- mx27_camera_emma_buf_init(icd, bytesperline);
} else if (cpu_is_mx25()) {
writel((bytesperline * icd->user_height) >> 2,
pcdev->base_csi + CSIRXCNT);
@@ -911,15 +1097,184 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd,
return ret;
}
+static int mx2_camera_get_formats(struct soc_camera_device *icd,
+ unsigned int idx,
+ struct soc_camera_format_xlate *xlate)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ const struct soc_mbus_pixelfmt *fmt;
+ struct device *dev = icd->parent;
+ enum v4l2_mbus_pixelcode code;
+ int ret, formats = 0;
+
+ ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+ if (ret < 0)
+ /* no more formats */
+ return 0;
+
+ fmt = soc_mbus_get_fmtdesc(code);
+ if (!fmt) {
+ dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
+ return 0;
+ }
+
+ if (code == V4L2_MBUS_FMT_YUYV8_2X8) {
+ formats++;
+ if (xlate) {
+ /*
+ * CH2 can output YUV420 which is a standard format in
+ * soc_mediabus.c
+ */
+ xlate->host_fmt =
+ soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_1_5X8);
+ xlate->code = code;
+ dev_dbg(dev, "Providing host format %s for sensor code %d\n",
+ xlate->host_fmt->name, code);
+ xlate++;
+ }
+ }
+
+ /* Generic pass-trough */
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = fmt;
+ xlate->code = code;
+ xlate++;
+ }
+ return formats;
+}
+
+static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev,
+ struct v4l2_mbus_framefmt *mf_in,
+ struct v4l2_pix_format *pix_out, bool apply)
+{
+ int num, den;
+ unsigned long m;
+ int i, dir;
+
+ for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
+ struct emma_prp_resize tmprsz;
+ unsigned char *s = tmprsz.s;
+ int len = 0;
+ int in, out;
+
+ if (dir == RESIZE_DIR_H) {
+ in = mf_in->width;
+ out = pix_out->width;
+ } else {
+ in = mf_in->height;
+ out = pix_out->height;
+ }
+
+ if (in < out)
+ return -EINVAL;
+ else if (in == out)
+ continue;
+
+ /* Calculate ratio */
+ m = gcd(in, out);
+ num = in / m;
+ den = out / m;
+ if (num > RESIZE_NUM_MAX)
+ return -EINVAL;
+
+ if ((num >= 2 * den) && (den == 1) &&
+ (num < 9) && (!(num & 0x01))) {
+ int sum = 0;
+ int j;
+
+ /* Average scaling for >= 2:1 ratios */
+ /* Support can be added for num >=9 and odd values */
+
+ tmprsz.algo = RESIZE_ALGO_AVERAGING;
+ len = num;
+
+ for (i = 0; i < (len / 2); i++)
+ s[i] = 8;
+
+ do {
+ for (i = 0; i < (len / 2); i++) {
+ s[i] = s[i] >> 1;
+ sum = 0;
+ for (j = 0; j < (len / 2); j++)
+ sum += s[j];
+ if (sum == 4)
+ break;
+ }
+ } while (sum != 4);
+
+ for (i = (len / 2); i < len; i++)
+ s[i] = s[len - i - 1];
+
+ s[len - 1] |= SZ_COEF;
+ } else {
+ /* bilinear scaling for < 2:1 ratios */
+ int v; /* overflow counter */
+ int coeff, nxt; /* table output */
+ int in_pos_inc = 2 * den;
+ int out_pos = num;
+ int out_pos_inc = 2 * num;
+ int init_carry = num - den;
+ int carry = init_carry;
+
+ tmprsz.algo = RESIZE_ALGO_BILINEAR;
+ v = den + in_pos_inc;
+ do {
+ coeff = v - out_pos;
+ out_pos += out_pos_inc;
+ carry += out_pos_inc;
+ for (nxt = 0; v < out_pos; nxt++) {
+ v += in_pos_inc;
+ carry -= in_pos_inc;
+ }
+
+ if (len > RESIZE_NUM_MAX)
+ return -EINVAL;
+
+ coeff = ((coeff << BC_COEF) +
+ (in_pos_inc >> 1)) / in_pos_inc;
+
+ if (coeff >= (SZ_COEF - 1))
+ coeff--;
+
+ coeff |= SZ_COEF;
+ s[len] = (unsigned char)coeff;
+ len++;
+
+ for (i = 1; i < nxt; i++) {
+ if (len >= RESIZE_NUM_MAX)
+ return -EINVAL;
+ s[len] = 0;
+ len++;
+ }
+ } while (carry != init_carry);
+ }
+ tmprsz.len = len;
+ if (dir == RESIZE_DIR_H)
+ mf_in->width = pix_out->width;
+ else
+ mf_in->height = pix_out->height;
+
+ if (apply)
+ memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz));
+ }
+ return 0;
+}
+
static int mx2_camera_set_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_mbus_framefmt mf;
int ret;
+ dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
+ __func__, pix->width, pix->height);
+
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
if (!xlate) {
dev_warn(icd->parent, "Format %x not found\n",
@@ -937,6 +1292,22 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
if (ret < 0 && ret != -ENOIOCTLCMD)
return ret;
+ /* Store width and height returned by the sensor for resizing */
+ pcdev->s_width = mf.width;
+ pcdev->s_height = mf.height;
+ dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
+ __func__, pcdev->s_width, pcdev->s_height);
+
+ pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
+ xlate->host_fmt->fourcc);
+
+ memset(pcdev->resizing, 0, sizeof(pcdev->resizing));
+ if ((mf.width != pix->width || mf.height != pix->height) &&
+ pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
+ if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0)
+ dev_dbg(icd->parent, "%s: can't resize\n", __func__);
+ }
+
if (mf.code != xlate->code)
return -EINVAL;
@@ -946,6 +1317,9 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
pix->colorspace = mf.colorspace;
icd->current_fmt = xlate;
+ dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
+ __func__, pix->width, pix->height);
+
return 0;
}
@@ -957,9 +1331,14 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_mbus_framefmt mf;
__u32 pixfmt = pix->pixelformat;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
unsigned int width_limit;
int ret;
+ dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
+ __func__, pix->width, pix->height);
+
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (pixfmt && !xlate) {
dev_warn(icd->parent, "Format %x not found\n", pixfmt);
@@ -1009,9 +1388,28 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
if (ret < 0)
return ret;
+ dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
+ __func__, pcdev->s_width, pcdev->s_height);
+
+ /* If the sensor does not support image size try PrP resizing */
+ pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
+ xlate->host_fmt->fourcc);
+
+ memset(pcdev->resizing, 0, sizeof(pcdev->resizing));
+ if ((mf.width != pix->width || mf.height != pix->height) &&
+ pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
+ if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0)
+ dev_dbg(icd->parent, "%s: can't resize\n", __func__);
+ }
+
if (mf.field == V4L2_FIELD_ANY)
mf.field = V4L2_FIELD_NONE;
- if (mf.field != V4L2_FIELD_NONE) {
+ /*
+ * Driver supports interlaced images provided they have
+ * both fields so that they can be processed as if they
+ * were progressive.
+ */
+ if (mf.field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf.field)) {
dev_err(icd->parent, "Field type %d unsupported.\n",
mf.field);
return -EINVAL;
@@ -1022,6 +1420,9 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
pix->field = mf.field;
pix->colorspace = mf.colorspace;
+ dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
+ __func__, pix->width, pix->height);
+
return 0;
}
@@ -1035,136 +1436,11 @@ static int mx2_camera_querycap(struct soc_camera_host *ici,
return 0;
}
-static int mx2_camera_reqbufs(struct soc_camera_device *icd,
- struct v4l2_requestbuffers *p)
-{
- int i;
-
- for (i = 0; i < p->count; i++) {
- struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i],
- struct mx2_buffer, vb);
- INIT_LIST_HEAD(&buf->vb.queue);
- }
-
- return 0;
-}
-
-#ifdef CONFIG_MACH_MX27
-static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state)
-{
- struct videobuf_buffer *vb;
- struct mx2_buffer *buf;
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&pcdev->lock, flags);
-
- if (!pcdev->active) {
- dev_err(pcdev->dev, "%s called with no active buffer!\n",
- __func__);
- goto out;
- }
-
- vb = &pcdev->active->vb;
- buf = container_of(vb, struct mx2_buffer, vb);
- WARN_ON(list_empty(&vb->queue));
- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
-
- /* _init is used to debug races, see comment in pxa_camera_reqbufs() */
- list_del_init(&vb->queue);
- vb->state = state;
- do_gettimeofday(&vb->ts);
- vb->field_count++;
-
- wake_up(&vb->done);
-
- if (list_empty(&pcdev->capture)) {
- pcdev->active = NULL;
- goto out;
- }
-
- pcdev->active = list_entry(pcdev->capture.next,
- struct mx2_buffer, vb.queue);
-
- vb = &pcdev->active->vb;
- vb->state = VIDEOBUF_ACTIVE;
-
- ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb),
- vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ);
-
- if (ret) {
- vb->state = VIDEOBUF_ERROR;
- pcdev->active = NULL;
- wake_up(&vb->done);
- }
-
-out:
- spin_unlock_irqrestore(&pcdev->lock, flags);
-}
-
-static void mx27_camera_dma_err_callback(int channel, void *data, int err)
-{
- struct mx2_camera_dev *pcdev = data;
-
- mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR);
-}
-
-static void mx27_camera_dma_callback(int channel, void *data)
-{
- struct mx2_camera_dev *pcdev = data;
-
- mx27_camera_frame_done(pcdev, VIDEOBUF_DONE);
-}
-
-#define DMA_REQ_CSI_RX 31 /* FIXME: Add this to a resource */
-
-static int __devinit mx27_camera_dma_init(struct platform_device *pdev,
- struct mx2_camera_dev *pcdev)
-{
- int err;
-
- pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH);
- if (pcdev->dma < 0) {
- dev_err(&pdev->dev, "%s failed to request DMA channel\n",
- __func__);
- return pcdev->dma;
- }
-
- err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback,
- mx27_camera_dma_err_callback, pcdev);
- if (err) {
- dev_err(&pdev->dev, "%s failed to set DMA callback\n",
- __func__);
- goto err_out;
- }
-
- err = imx_dma_config_channel(pcdev->dma,
- IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO,
- IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
- DMA_REQ_CSI_RX, 1);
- if (err) {
- dev_err(&pdev->dev, "%s failed to config DMA channel\n",
- __func__);
- goto err_out;
- }
-
- imx_dma_config_burstlen(pcdev->dma, 64);
-
- return 0;
-
-err_out:
- imx_dma_free(pcdev->dma);
-
- return err;
-}
-#endif /* CONFIG_MACH_MX27 */
-
static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
{
struct soc_camera_device *icd = file->private_data;
- return videobuf_poll_stream(file, &icd->vb_vidq, pt);
+ return vb2_poll(&icd->vb2_vidq, file, pt);
}
static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
@@ -1173,105 +1449,150 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
.remove = mx2_camera_remove_device,
.set_fmt = mx2_camera_set_fmt,
.set_crop = mx2_camera_set_crop,
+ .get_formats = mx2_camera_get_formats,
.try_fmt = mx2_camera_try_fmt,
- .init_videobuf = mx2_camera_init_videobuf,
- .reqbufs = mx2_camera_reqbufs,
+ .init_videobuf2 = mx2_camera_init_videobuf,
.poll = mx2_camera_poll,
.querycap = mx2_camera_querycap,
.set_bus_param = mx2_camera_set_bus_param,
};
static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
- int bufnum, int state)
+ int bufnum, bool err)
{
+#ifdef DEBUG
+ struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+#endif
+ struct mx2_buf_internal *ibuf;
struct mx2_buffer *buf;
- struct videobuf_buffer *vb;
+ struct vb2_buffer *vb;
unsigned long phys;
- if (!list_empty(&pcdev->active_bufs)) {
- buf = list_entry(pcdev->active_bufs.next,
- struct mx2_buffer, vb.queue);
+ ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal,
+ queue);
- BUG_ON(buf->bufnum != bufnum);
+ BUG_ON(ibuf->bufnum != bufnum);
+
+ if (ibuf->discard) {
+ /*
+ * Discard buffer must not be returned to user space.
+ * Just return it to the discard queue.
+ */
+ list_move_tail(pcdev->active_bufs.next, &pcdev->discard);
+ } else {
+ buf = mx2_ibuf_to_buf(ibuf);
vb = &buf->vb;
#ifdef DEBUG
- phys = videobuf_to_dma_contig(vb);
- if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum)
- != phys) {
- dev_err(pcdev->dev, "%p != %p\n", phys,
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ if (prp->cfg.channel == 1) {
+ if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR +
+ 4 * bufnum) != phys) {
+ dev_err(pcdev->dev, "%lx != %x\n", phys,
+ readl(pcdev->base_emma +
+ PRP_DEST_RGB1_PTR + 4 * bufnum));
+ }
+ } else {
+ if (readl(pcdev->base_emma + PRP_DEST_Y_PTR -
+ 0x14 * bufnum) != phys) {
+ dev_err(pcdev->dev, "%lx != %x\n", phys,
readl(pcdev->base_emma +
- PRP_DEST_RGB1_PTR +
- 4 * bufnum));
+ PRP_DEST_Y_PTR - 0x14 * bufnum));
+ }
}
#endif
- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb,
- vb->baddr, vb->bsize);
-
- list_del(&vb->queue);
- vb->state = state;
- do_gettimeofday(&vb->ts);
- vb->field_count++;
+ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb,
+ vb2_plane_vaddr(vb, 0),
+ vb2_get_plane_payload(vb, 0));
- wake_up(&vb->done);
+ list_del_init(&buf->internal.queue);
+ do_gettimeofday(&vb->v4l2_buf.timestamp);
+ vb->v4l2_buf.sequence = pcdev->frame_count;
+ if (err)
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ else
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
}
+ pcdev->frame_count++;
+
if (list_empty(&pcdev->capture)) {
- writel(pcdev->discard_buffer_dma, pcdev->base_emma +
- PRP_DEST_RGB1_PTR + 4 * bufnum);
+ if (list_empty(&pcdev->discard)) {
+ dev_warn(pcdev->dev, "%s: trying to access empty discard list\n",
+ __func__);
+ return;
+ }
+
+ ibuf = list_first_entry(&pcdev->discard,
+ struct mx2_buf_internal, queue);
+ ibuf->bufnum = bufnum;
+
+ list_move_tail(pcdev->discard.next, &pcdev->active_bufs);
+ mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum);
return;
}
- buf = list_entry(pcdev->capture.next,
- struct mx2_buffer, vb.queue);
+ buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+ internal.queue);
- buf->bufnum = !bufnum;
+ buf->internal.bufnum = bufnum;
list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
vb = &buf->vb;
- vb->state = VIDEOBUF_ACTIVE;
+ buf->state = MX2_STATE_ACTIVE;
- phys = videobuf_to_dma_contig(vb);
- writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ mx27_update_emma_buf(pcdev, phys, bufnum);
}
static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
{
struct mx2_camera_dev *pcdev = data;
unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS);
- struct mx2_buffer *buf;
+ struct mx2_buf_internal *ibuf;
+
+ spin_lock(&pcdev->lock);
+
+ if (list_empty(&pcdev->active_bufs)) {
+ dev_warn(pcdev->dev, "%s: called while active list is empty\n",
+ __func__);
+
+ if (!status) {
+ spin_unlock(&pcdev->lock);
+ return IRQ_NONE;
+ }
+ }
if (status & (1 << 7)) { /* overflow */
- u32 cntl;
- /*
- * We only disable channel 1 here since this is the only
- * enabled channel
- *
- * FIXME: the correct DMA overflow handling should be resetting
- * the buffer, returning an error frame, and continuing with
- * the next one.
- */
- cntl = readl(pcdev->base_emma + PRP_CNTL);
- writel(cntl & ~PRP_CNTL_CH1EN, pcdev->base_emma + PRP_CNTL);
+ u32 cntl = readl(pcdev->base_emma + PRP_CNTL);
+ writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN),
+ pcdev->base_emma + PRP_CNTL);
writel(cntl, pcdev->base_emma + PRP_CNTL);
- }
- if ((status & (3 << 5)) == (3 << 5)
- && !list_empty(&pcdev->active_bufs)) {
+
+ ibuf = list_first_entry(&pcdev->active_bufs,
+ struct mx2_buf_internal, queue);
+ mx27_camera_frame_done_emma(pcdev,
+ ibuf->bufnum, true);
+
+ status &= ~(1 << 7);
+ } else if (((status & (3 << 5)) == (3 << 5)) ||
+ ((status & (3 << 3)) == (3 << 3))) {
/*
* Both buffers have triggered, process the one we're expecting
* to first
*/
- buf = list_entry(pcdev->active_bufs.next,
- struct mx2_buffer, vb.queue);
- mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE);
- status &= ~(1 << (6 - buf->bufnum)); /* mark processed */
+ ibuf = list_first_entry(&pcdev->active_bufs,
+ struct mx2_buf_internal, queue);
+ mx27_camera_frame_done_emma(pcdev, ibuf->bufnum, false);
+ status &= ~(1 << (6 - ibuf->bufnum)); /* mark processed */
+ } else if ((status & (1 << 6)) || (status & (1 << 4))) {
+ mx27_camera_frame_done_emma(pcdev, 0, false);
+ } else if ((status & (1 << 5)) || (status & (1 << 3))) {
+ mx27_camera_frame_done_emma(pcdev, 1, false);
}
- if (status & (1 << 6))
- mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE);
- if (status & (1 << 5))
- mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE);
+ spin_unlock(&pcdev->lock);
writel(status, pcdev->base_emma + PRP_INTRSTATUS);
return IRQ_HANDLED;
@@ -1334,8 +1655,6 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
struct resource *res_csi, *res_emma;
void __iomem *base_csi;
int irq_csi, irq_emma;
- irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq
- : mx27_camera_irq;
int err = 0;
dev_dbg(&pdev->dev, "initialising\n");
@@ -1357,22 +1676,11 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
pcdev->clk_csi = clk_get(&pdev->dev, NULL);
if (IS_ERR(pcdev->clk_csi)) {
+ dev_err(&pdev->dev, "Could not get csi clock\n");
err = PTR_ERR(pcdev->clk_csi);
goto exit_kfree;
}
- dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n",
- clk_get_rate(pcdev->clk_csi));
-
- /* Initialize DMA */
-#ifdef CONFIG_MACH_MX27
- if (cpu_is_mx27()) {
- err = mx27_camera_dma_init(pdev, pcdev);
- if (err)
- goto exit_clk_put;
- }
-#endif /* CONFIG_MACH_MX27 */
-
pcdev->res_csi = res_csi;
pcdev->pdata = pdev->dev.platform_data;
if (pcdev->pdata) {
@@ -1392,6 +1700,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&pcdev->capture);
INIT_LIST_HEAD(&pcdev->active_bufs);
+ INIT_LIST_HEAD(&pcdev->discard);
spin_lock_init(&pcdev->lock);
/*
@@ -1413,11 +1722,13 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
pcdev->base_dma = res_csi->start;
pcdev->dev = &pdev->dev;
- err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0,
- MX2_CAM_DRV_NAME, pcdev);
- if (err) {
- dev_err(pcdev->dev, "Camera interrupt register failed \n");
- goto exit_iounmap;
+ if (cpu_is_mx25()) {
+ err = request_irq(pcdev->irq_csi, mx25_camera_irq, 0,
+ MX2_CAM_DRV_NAME, pcdev);
+ if (err) {
+ dev_err(pcdev->dev, "Camera interrupt register failed \n");
+ goto exit_iounmap;
+ }
}
if (cpu_is_mx27()) {
@@ -1425,14 +1736,15 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1);
irq_emma = platform_get_irq(pdev, 1);
- if (res_emma && irq_emma >= 0) {
- dev_info(&pdev->dev, "Using EMMA\n");
- pcdev->use_emma = 1;
- pcdev->res_emma = res_emma;
- pcdev->irq_emma = irq_emma;
- if (mx27_camera_emma_init(pcdev))
- goto exit_free_irq;
+ if (!res_emma || !irq_emma) {
+ dev_err(&pdev->dev, "no EMMA resources\n");
+ goto exit_free_irq;
}
+
+ pcdev->res_emma = res_emma;
+ pcdev->irq_emma = irq_emma;
+ if (mx27_camera_emma_init(pcdev))
+ goto exit_free_irq;
}
pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME,
@@ -1440,6 +1752,12 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
pcdev->soc_host.priv = pcdev;
pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
pcdev->soc_host.nr = pdev->id;
+
+ pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(pcdev->alloc_ctx)) {
+ err = PTR_ERR(pcdev->alloc_ctx);
+ goto eallocctx;
+ }
err = soc_camera_host_register(&pcdev->soc_host);
if (err)
goto exit_free_emma;
@@ -1450,26 +1768,24 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
return 0;
exit_free_emma:
- if (mx27_camera_emma(pcdev)) {
+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+eallocctx:
+ if (cpu_is_mx27()) {
free_irq(pcdev->irq_emma, pcdev);
clk_disable(pcdev->clk_emma);
clk_put(pcdev->clk_emma);
iounmap(pcdev->base_emma);
- release_mem_region(res_emma->start, resource_size(res_emma));
+ release_mem_region(pcdev->res_emma->start, resource_size(pcdev->res_emma));
}
exit_free_irq:
- free_irq(pcdev->irq_csi, pcdev);
+ if (cpu_is_mx25())
+ free_irq(pcdev->irq_csi, pcdev);
exit_iounmap:
iounmap(base_csi);
exit_release:
release_mem_region(res_csi->start, resource_size(res_csi));
exit_dma_free:
-#ifdef CONFIG_MACH_MX27
- if (cpu_is_mx27())
- imx_dma_free(pcdev->dma);
-exit_clk_put:
clk_put(pcdev->clk_csi);
-#endif /* CONFIG_MACH_MX27 */
exit_kfree:
kfree(pcdev);
exit:
@@ -1484,19 +1800,18 @@ static int __devexit mx2_camera_remove(struct platform_device *pdev)
struct resource *res;
clk_put(pcdev->clk_csi);
-#ifdef CONFIG_MACH_MX27
+ if (cpu_is_mx25())
+ free_irq(pcdev->irq_csi, pcdev);
if (cpu_is_mx27())
- imx_dma_free(pcdev->dma);
-#endif /* CONFIG_MACH_MX27 */
- free_irq(pcdev->irq_csi, pcdev);
- if (mx27_camera_emma(pcdev))
free_irq(pcdev->irq_emma, pcdev);
soc_camera_host_unregister(&pcdev->soc_host);
+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+
iounmap(pcdev->base_csi);
- if (mx27_camera_emma(pcdev)) {
+ if (cpu_is_mx27()) {
clk_disable(pcdev->clk_emma);
clk_put(pcdev->clk_emma);
iounmap(pcdev->base_emma);
diff --git a/drivers/media/video/mx2_emmaprp.c b/drivers/media/video/mx2_emmaprp.c
new file mode 100644
index 000000000000..ba89a7401c8c
--- /dev/null
+++ b/drivers/media/video/mx2_emmaprp.c
@@ -0,0 +1,1008 @@
+/*
+ * Support eMMa-PrP through mem2mem framework.
+ *
+ * eMMa-PrP is a piece of HW that allows fetching buffers
+ * from one memory location and do several operations on
+ * them such as scaling or format conversion giving, as a result
+ * a new processed buffer in another memory location.
+ *
+ * Based on mem2mem_testdev.c by Pawel Osciak.
+ *
+ * Copyright (c) 2011 Vista Silicon S.L.
+ * Javier Martin <javier.martin@vista-silicon.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
+ */
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+#include <asm/sizes.h>
+
+#define EMMAPRP_MODULE_NAME "mem2mem-emmaprp"
+
+MODULE_DESCRIPTION("Mem-to-mem device which supports eMMa-PrP present in mx2 SoCs");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.1");
+
+static bool debug;
+module_param(debug, bool, 0644);
+
+#define MIN_W 32
+#define MIN_H 32
+#define MAX_W 2040
+#define MAX_H 2046
+
+#define S_ALIGN 1 /* multiple of 2 */
+#define W_ALIGN_YUV420 3 /* multiple of 8 */
+#define W_ALIGN_OTHERS 2 /* multiple of 4 */
+#define H_ALIGN 1 /* multiple of 2 */
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE (1 << 0)
+#define MEM2MEM_OUTPUT (1 << 1)
+
+#define MEM2MEM_NAME "m2m-emmaprp"
+
+/* In bytes, per queue */
+#define MEM2MEM_VID_MEM_LIMIT SZ_16M
+
+#define dprintk(dev, fmt, arg...) \
+ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+/* EMMA PrP */
+#define PRP_CNTL 0x00
+#define PRP_INTR_CNTL 0x04
+#define PRP_INTRSTATUS 0x08
+#define PRP_SOURCE_Y_PTR 0x0c
+#define PRP_SOURCE_CB_PTR 0x10
+#define PRP_SOURCE_CR_PTR 0x14
+#define PRP_DEST_RGB1_PTR 0x18
+#define PRP_DEST_RGB2_PTR 0x1c
+#define PRP_DEST_Y_PTR 0x20
+#define PRP_DEST_CB_PTR 0x24
+#define PRP_DEST_CR_PTR 0x28
+#define PRP_SRC_FRAME_SIZE 0x2c
+#define PRP_DEST_CH1_LINE_STRIDE 0x30
+#define PRP_SRC_PIXEL_FORMAT_CNTL 0x34
+#define PRP_CH1_PIXEL_FORMAT_CNTL 0x38
+#define PRP_CH1_OUT_IMAGE_SIZE 0x3c
+#define PRP_CH2_OUT_IMAGE_SIZE 0x40
+#define PRP_SRC_LINE_STRIDE 0x44
+#define PRP_CSC_COEF_012 0x48
+#define PRP_CSC_COEF_345 0x4c
+#define PRP_CSC_COEF_678 0x50
+#define PRP_CH1_RZ_HORI_COEF1 0x54
+#define PRP_CH1_RZ_HORI_COEF2 0x58
+#define PRP_CH1_RZ_HORI_VALID 0x5c
+#define PRP_CH1_RZ_VERT_COEF1 0x60
+#define PRP_CH1_RZ_VERT_COEF2 0x64
+#define PRP_CH1_RZ_VERT_VALID 0x68
+#define PRP_CH2_RZ_HORI_COEF1 0x6c
+#define PRP_CH2_RZ_HORI_COEF2 0x70
+#define PRP_CH2_RZ_HORI_VALID 0x74
+#define PRP_CH2_RZ_VERT_COEF1 0x78
+#define PRP_CH2_RZ_VERT_COEF2 0x7c
+#define PRP_CH2_RZ_VERT_VALID 0x80
+
+#define PRP_CNTL_CH1EN (1 << 0)
+#define PRP_CNTL_CH2EN (1 << 1)
+#define PRP_CNTL_CSIEN (1 << 2)
+#define PRP_CNTL_DATA_IN_YUV420 (0 << 3)
+#define PRP_CNTL_DATA_IN_YUV422 (1 << 3)
+#define PRP_CNTL_DATA_IN_RGB16 (2 << 3)
+#define PRP_CNTL_DATA_IN_RGB32 (3 << 3)
+#define PRP_CNTL_CH1_OUT_RGB8 (0 << 5)
+#define PRP_CNTL_CH1_OUT_RGB16 (1 << 5)
+#define PRP_CNTL_CH1_OUT_RGB32 (2 << 5)
+#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5)
+#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7)
+#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
+#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7)
+#define PRP_CNTL_CH1_LEN (1 << 9)
+#define PRP_CNTL_CH2_LEN (1 << 10)
+#define PRP_CNTL_SKIP_FRAME (1 << 11)
+#define PRP_CNTL_SWRST (1 << 12)
+#define PRP_CNTL_CLKEN (1 << 13)
+#define PRP_CNTL_WEN (1 << 14)
+#define PRP_CNTL_CH1BYP (1 << 15)
+#define PRP_CNTL_IN_TSKIP(x) ((x) << 16)
+#define PRP_CNTL_CH1_TSKIP(x) ((x) << 19)
+#define PRP_CNTL_CH2_TSKIP(x) ((x) << 22)
+#define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25)
+#define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27)
+#define PRP_CNTL_CH2B1EN (1 << 29)
+#define PRP_CNTL_CH2B2EN (1 << 30)
+#define PRP_CNTL_CH2FEN (1 << 31)
+
+#define PRP_SIZE_HEIGHT(x) (x)
+#define PRP_SIZE_WIDTH(x) ((x) << 16)
+
+/* IRQ Enable and status register */
+#define PRP_INTR_RDERR (1 << 0)
+#define PRP_INTR_CH1WERR (1 << 1)
+#define PRP_INTR_CH2WERR (1 << 2)
+#define PRP_INTR_CH1FC (1 << 3)
+#define PRP_INTR_CH2FC (1 << 5)
+#define PRP_INTR_LBOVF (1 << 7)
+#define PRP_INTR_CH2OVF (1 << 8)
+
+#define PRP_INTR_ST_RDERR (1 << 0)
+#define PRP_INTR_ST_CH1WERR (1 << 1)
+#define PRP_INTR_ST_CH2WERR (1 << 2)
+#define PRP_INTR_ST_CH2B2CI (1 << 3)
+#define PRP_INTR_ST_CH2B1CI (1 << 4)
+#define PRP_INTR_ST_CH1B2CI (1 << 5)
+#define PRP_INTR_ST_CH1B1CI (1 << 6)
+#define PRP_INTR_ST_LBOVF (1 << 7)
+#define PRP_INTR_ST_CH2OVF (1 << 8)
+
+struct emmaprp_fmt {
+ char *name;
+ u32 fourcc;
+ /* Types the format can be used for */
+ u32 types;
+};
+
+static struct emmaprp_fmt formats[] = {
+ {
+ .name = "YUV 4:2:0 Planar",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .types = MEM2MEM_CAPTURE,
+ },
+ {
+ .name = "4:2:2, packed, YUYV",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .types = MEM2MEM_OUTPUT,
+ },
+};
+
+/* Per-queue, driver-specific private data */
+struct emmaprp_q_data {
+ unsigned int width;
+ unsigned int height;
+ unsigned int sizeimage;
+ struct emmaprp_fmt *fmt;
+};
+
+enum {
+ V4L2_M2M_SRC = 0,
+ V4L2_M2M_DST = 1,
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static struct emmaprp_fmt *find_format(struct v4l2_format *f)
+{
+ struct emmaprp_fmt *fmt;
+ unsigned int k;
+
+ for (k = 0; k < NUM_FORMATS; k++) {
+ fmt = &formats[k];
+ if (fmt->fourcc == f->fmt.pix.pixelformat)
+ break;
+ }
+
+ if (k == NUM_FORMATS)
+ return NULL;
+
+ return &formats[k];
+}
+
+struct emmaprp_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device *vfd;
+
+ struct mutex dev_mutex;
+ spinlock_t irqlock;
+
+ int irq_emma;
+ void __iomem *base_emma;
+ struct clk *clk_emma;
+ struct resource *res_emma;
+
+ struct v4l2_m2m_dev *m2m_dev;
+ struct vb2_alloc_ctx *alloc_ctx;
+};
+
+struct emmaprp_ctx {
+ struct emmaprp_dev *dev;
+ /* Abort requested by m2m */
+ int aborting;
+ struct emmaprp_q_data q_data[2];
+ struct v4l2_m2m_ctx *m2m_ctx;
+};
+
+static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ return &(ctx->q_data[V4L2_M2M_SRC]);
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return &(ctx->q_data[V4L2_M2M_DST]);
+ default:
+ BUG();
+ }
+ return NULL;
+}
+
+/*
+ * mem2mem callbacks
+ */
+static void emmaprp_job_abort(void *priv)
+{
+ struct emmaprp_ctx *ctx = priv;
+ struct emmaprp_dev *pcdev = ctx->dev;
+
+ ctx->aborting = 1;
+
+ dprintk(pcdev, "Aborting task\n");
+
+ v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void emmaprp_lock(void *priv)
+{
+ struct emmaprp_ctx *ctx = priv;
+ struct emmaprp_dev *pcdev = ctx->dev;
+ mutex_lock(&pcdev->dev_mutex);
+}
+
+static void emmaprp_unlock(void *priv)
+{
+ struct emmaprp_ctx *ctx = priv;
+ struct emmaprp_dev *pcdev = ctx->dev;
+ mutex_unlock(&pcdev->dev_mutex);
+}
+
+static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev)
+{
+ dprintk(pcdev,
+ "eMMa-PrP Registers:\n"
+ " SOURCE_Y_PTR = 0x%08X\n"
+ " SRC_FRAME_SIZE = 0x%08X\n"
+ " DEST_Y_PTR = 0x%08X\n"
+ " DEST_CR_PTR = 0x%08X\n"
+ " DEST_CB_PTR = 0x%08X\n"
+ " CH2_OUT_IMAGE_SIZE = 0x%08X\n"
+ " CNTL = 0x%08X\n",
+ readl(pcdev->base_emma + PRP_SOURCE_Y_PTR),
+ readl(pcdev->base_emma + PRP_SRC_FRAME_SIZE),
+ readl(pcdev->base_emma + PRP_DEST_Y_PTR),
+ readl(pcdev->base_emma + PRP_DEST_CR_PTR),
+ readl(pcdev->base_emma + PRP_DEST_CB_PTR),
+ readl(pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE),
+ readl(pcdev->base_emma + PRP_CNTL));
+}
+
+static void emmaprp_device_run(void *priv)
+{
+ struct emmaprp_ctx *ctx = priv;
+ struct emmaprp_q_data *s_q_data, *d_q_data;
+ struct vb2_buffer *src_buf, *dst_buf;
+ struct emmaprp_dev *pcdev = ctx->dev;
+ unsigned int s_width, s_height;
+ unsigned int d_width, d_height;
+ unsigned int d_size;
+ dma_addr_t p_in, p_out;
+ u32 tmp;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+ s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ s_width = s_q_data->width;
+ s_height = s_q_data->height;
+
+ d_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ d_width = d_q_data->width;
+ d_height = d_q_data->height;
+ d_size = d_width * d_height;
+
+ p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+ if (!p_in || !p_out) {
+ v4l2_err(&pcdev->v4l2_dev,
+ "Acquiring kernel pointers to buffers failed\n");
+ return;
+ }
+
+ /* Input frame parameters */
+ writel(p_in, pcdev->base_emma + PRP_SOURCE_Y_PTR);
+ writel(PRP_SIZE_WIDTH(s_width) | PRP_SIZE_HEIGHT(s_height),
+ pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+
+ /* Output frame parameters */
+ writel(p_out, pcdev->base_emma + PRP_DEST_Y_PTR);
+ writel(p_out + d_size, pcdev->base_emma + PRP_DEST_CB_PTR);
+ writel(p_out + d_size + (d_size >> 2),
+ pcdev->base_emma + PRP_DEST_CR_PTR);
+ writel(PRP_SIZE_WIDTH(d_width) | PRP_SIZE_HEIGHT(d_height),
+ pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
+
+ /* IRQ configuration */
+ tmp = readl(pcdev->base_emma + PRP_INTR_CNTL);
+ writel(tmp | PRP_INTR_RDERR |
+ PRP_INTR_CH2WERR |
+ PRP_INTR_CH2FC,
+ pcdev->base_emma + PRP_INTR_CNTL);
+
+ emmaprp_dump_regs(pcdev);
+
+ /* Enable transfer */
+ tmp = readl(pcdev->base_emma + PRP_CNTL);
+ writel(tmp | PRP_CNTL_CH2_OUT_YUV420 |
+ PRP_CNTL_DATA_IN_YUV422 |
+ PRP_CNTL_CH2EN,
+ pcdev->base_emma + PRP_CNTL);
+}
+
+static irqreturn_t emmaprp_irq(int irq_emma, void *data)
+{
+ struct emmaprp_dev *pcdev = data;
+ struct emmaprp_ctx *curr_ctx;
+ struct vb2_buffer *src_vb, *dst_vb;
+ unsigned long flags;
+ u32 irqst;
+
+ /* Check irq flags and clear irq */
+ irqst = readl(pcdev->base_emma + PRP_INTRSTATUS);
+ writel(irqst, pcdev->base_emma + PRP_INTRSTATUS);
+ dprintk(pcdev, "irqst = 0x%08x\n", irqst);
+
+ curr_ctx = v4l2_m2m_get_curr_priv(pcdev->m2m_dev);
+ if (curr_ctx == NULL) {
+ pr_err("Instance released before the end of transaction\n");
+ return IRQ_HANDLED;
+ }
+
+ if (!curr_ctx->aborting) {
+ if ((irqst & PRP_INTR_ST_RDERR) ||
+ (irqst & PRP_INTR_ST_CH2WERR)) {
+ pr_err("PrP bus error ocurred, this transfer is probably corrupted\n");
+ writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
+ } else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */
+ src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+ spin_lock_irqsave(&pcdev->irqlock, flags);
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+ spin_unlock_irqrestore(&pcdev->irqlock, flags);
+ }
+ }
+
+ v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
+ return IRQ_HANDLED;
+}
+
+/*
+ * video ioctls
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
+ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+ int i, num;
+ struct emmaprp_fmt *fmt;
+
+ num = 0;
+
+ for (i = 0; i < NUM_FORMATS; ++i) {
+ if (formats[i].types & type) {
+ /* index-th format of type type found ? */
+ if (num == f->index)
+ break;
+ /* Correct type but haven't reached our index yet,
+ * just increment per-type index */
+ ++num;
+ }
+ }
+
+ if (i < NUM_FORMATS) {
+ /* Format found */
+ fmt = &formats[i];
+ strlcpy(f->description, fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = fmt->fourcc;
+ return 0;
+ }
+
+ /* Format not found */
+ return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return enum_fmt(f, MEM2MEM_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return enum_fmt(f, MEM2MEM_OUTPUT);
+}
+
+static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct emmaprp_q_data *q_data;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = get_q_data(ctx, f->type);
+
+ f->fmt.pix.width = q_data->width;
+ f->fmt.pix.height = q_data->height;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.pixelformat = q_data->fmt->fourcc;
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+ f->fmt.pix.bytesperline = q_data->width * 3 / 2;
+ else /* YUYV */
+ f->fmt.pix.bytesperline = q_data->width * 2;
+ f->fmt.pix.sizeimage = q_data->sizeimage;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f)
+{
+ enum v4l2_field field;
+
+
+ if (!find_format(f))
+ return -EINVAL;
+
+ field = f->fmt.pix.field;
+ if (field == V4L2_FIELD_ANY)
+ field = V4L2_FIELD_NONE;
+ else if (V4L2_FIELD_NONE != field)
+ return -EINVAL;
+
+ /* V4L2 specification suggests the driver corrects the format struct
+ * if any of the dimensions is unsupported */
+ f->fmt.pix.field = field;
+
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
+ v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+ W_ALIGN_YUV420, &f->fmt.pix.height,
+ MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+ } else {
+ v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+ W_ALIGN_OTHERS, &f->fmt.pix.height,
+ MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ }
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct emmaprp_fmt *fmt;
+ struct emmaprp_ctx *ctx = priv;
+
+ fmt = find_format(f);
+ if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ return vidioc_try_fmt(f);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct emmaprp_fmt *fmt;
+ struct emmaprp_ctx *ctx = priv;
+
+ fmt = find_format(f);
+ if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ return vidioc_try_fmt(f);
+}
+
+static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
+{
+ struct emmaprp_q_data *q_data;
+ struct vb2_queue *vq;
+ int ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = get_q_data(ctx, f->type);
+ if (!q_data)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ ret = vidioc_try_fmt(f);
+ if (ret)
+ return ret;
+
+ q_data->fmt = find_format(f);
+ q_data->width = f->fmt.pix.width;
+ q_data->height = f->fmt.pix.height;
+ if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
+ q_data->sizeimage = q_data->width * q_data->height * 3 / 2;
+ else /* YUYV */
+ q_data->sizeimage = q_data->width * q_data->height * 2;
+
+ dprintk(ctx->dev,
+ "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+ f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+
+ ret = vidioc_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+
+ ret = vidioc_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct emmaprp_ctx *ctx = priv;
+
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct emmaprp_ctx *ctx = priv;
+
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct emmaprp_ctx *ctx = priv;
+
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct emmaprp_ctx *ctx = priv;
+
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct emmaprp_ctx *ctx = priv;
+
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct emmaprp_ctx *ctx = priv;
+
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
+
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+};
+
+
+/*
+ * Queue operations
+ */
+static int emmaprp_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct emmaprp_ctx *ctx = vb2_get_drv_priv(vq);
+ struct emmaprp_q_data *q_data;
+ unsigned int size, count = *nbuffers;
+
+ q_data = get_q_data(ctx, vq->type);
+
+ if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
+ size = q_data->width * q_data->height * 3 / 2;
+ else
+ size = q_data->width * q_data->height * 2;
+
+ while (size * count > MEM2MEM_VID_MEM_LIMIT)
+ (count)--;
+
+ *nplanes = 1;
+ *nbuffers = count;
+ sizes[0] = size;
+
+ alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+ dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
+
+ return 0;
+}
+
+static int emmaprp_buf_prepare(struct vb2_buffer *vb)
+{
+ struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct emmaprp_q_data *q_data;
+
+ dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
+
+ q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+ if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+ dprintk(ctx->dev, "%s data will not fit into plane"
+ "(%lu < %lu)\n", __func__,
+ vb2_plane_size(vb, 0),
+ (long)q_data->sizeimage);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+ return 0;
+}
+
+static void emmaprp_buf_queue(struct vb2_buffer *vb)
+{
+ struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static struct vb2_ops emmaprp_qops = {
+ .queue_setup = emmaprp_queue_setup,
+ .buf_prepare = emmaprp_buf_prepare,
+ .buf_queue = emmaprp_buf_queue,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct emmaprp_ctx *ctx = priv;
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->io_modes = VB2_MMAP;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &emmaprp_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->io_modes = VB2_MMAP;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &emmaprp_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+ return vb2_queue_init(dst_vq);
+}
+
+/*
+ * File operations
+ */
+static int emmaprp_open(struct file *file)
+{
+ struct emmaprp_dev *pcdev = video_drvdata(file);
+ struct emmaprp_ctx *ctx;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ file->private_data = ctx;
+ ctx->dev = pcdev;
+
+ ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
+
+ if (IS_ERR(ctx->m2m_ctx)) {
+ int ret = PTR_ERR(ctx->m2m_ctx);
+
+ kfree(ctx);
+ return ret;
+ }
+
+ clk_enable(pcdev->clk_emma);
+ ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1];
+ ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
+
+ dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+
+ return 0;
+}
+
+static int emmaprp_release(struct file *file)
+{
+ struct emmaprp_dev *pcdev = video_drvdata(file);
+ struct emmaprp_ctx *ctx = file->private_data;
+
+ dprintk(pcdev, "Releasing instance %p\n", ctx);
+
+ clk_disable(pcdev->clk_emma);
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ kfree(ctx);
+
+ return 0;
+}
+
+static unsigned int emmaprp_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct emmaprp_ctx *ctx = file->private_data;
+
+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct emmaprp_ctx *ctx = file->private_data;
+
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations emmaprp_fops = {
+ .owner = THIS_MODULE,
+ .open = emmaprp_open,
+ .release = emmaprp_release,
+ .poll = emmaprp_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = emmaprp_mmap,
+};
+
+static struct video_device emmaprp_videodev = {
+ .name = MEM2MEM_NAME,
+ .fops = &emmaprp_fops,
+ .ioctl_ops = &emmaprp_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+ .device_run = emmaprp_device_run,
+ .job_abort = emmaprp_job_abort,
+ .lock = emmaprp_lock,
+ .unlock = emmaprp_unlock,
+};
+
+static int emmaprp_probe(struct platform_device *pdev)
+{
+ struct emmaprp_dev *pcdev;
+ struct video_device *vfd;
+ struct resource *res_emma;
+ int irq_emma;
+ int ret;
+
+ pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL);
+ if (!pcdev)
+ return -ENOMEM;
+
+ spin_lock_init(&pcdev->irqlock);
+
+ pcdev->clk_emma = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pcdev->clk_emma)) {
+ ret = PTR_ERR(pcdev->clk_emma);
+ goto free_dev;
+ }
+
+ irq_emma = platform_get_irq(pdev, 0);
+ res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (irq_emma < 0 || res_emma == NULL) {
+ dev_err(&pdev->dev, "Missing platform resources data\n");
+ ret = -ENODEV;
+ goto free_clk;
+ }
+
+ ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
+ if (ret)
+ goto free_clk;
+
+ mutex_init(&pcdev->dev_mutex);
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto unreg_dev;
+ }
+
+ *vfd = emmaprp_videodev;
+ vfd->lock = &pcdev->dev_mutex;
+
+ video_set_drvdata(vfd, pcdev);
+ snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name);
+ pcdev->vfd = vfd;
+ v4l2_info(&pcdev->v4l2_dev, EMMAPRP_MODULE_NAME
+ " Device registered as /dev/video%d\n", vfd->num);
+
+ platform_set_drvdata(pdev, pcdev);
+
+ if (devm_request_mem_region(&pdev->dev, res_emma->start,
+ resource_size(res_emma), MEM2MEM_NAME) == NULL)
+ goto rel_vdev;
+
+ pcdev->base_emma = devm_ioremap(&pdev->dev, res_emma->start,
+ resource_size(res_emma));
+ if (!pcdev->base_emma)
+ goto rel_vdev;
+
+ pcdev->irq_emma = irq_emma;
+ pcdev->res_emma = res_emma;
+
+ if (devm_request_irq(&pdev->dev, pcdev->irq_emma, emmaprp_irq,
+ 0, MEM2MEM_NAME, pcdev) < 0)
+ goto rel_vdev;
+
+ pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(pcdev->alloc_ctx)) {
+ v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n");
+ ret = PTR_ERR(pcdev->alloc_ctx);
+ goto rel_vdev;
+ }
+
+ pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops);
+ if (IS_ERR(pcdev->m2m_dev)) {
+ v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n");
+ ret = PTR_ERR(pcdev->m2m_dev);
+ goto rel_ctx;
+ }
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
+ goto rel_m2m;
+ }
+
+ return 0;
+
+
+rel_m2m:
+ v4l2_m2m_release(pcdev->m2m_dev);
+rel_ctx:
+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+rel_vdev:
+ video_device_release(vfd);
+unreg_dev:
+ v4l2_device_unregister(&pcdev->v4l2_dev);
+free_clk:
+ clk_put(pcdev->clk_emma);
+free_dev:
+ kfree(pcdev);
+
+ return ret;
+}
+
+static int emmaprp_remove(struct platform_device *pdev)
+{
+ struct emmaprp_dev *pcdev = platform_get_drvdata(pdev);
+
+ v4l2_info(&pcdev->v4l2_dev, "Removing " EMMAPRP_MODULE_NAME);
+
+ video_unregister_device(pcdev->vfd);
+ v4l2_m2m_release(pcdev->m2m_dev);
+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+ v4l2_device_unregister(&pcdev->v4l2_dev);
+ clk_put(pcdev->clk_emma);
+ kfree(pcdev);
+
+ return 0;
+}
+
+static struct platform_driver emmaprp_pdrv = {
+ .probe = emmaprp_probe,
+ .remove = emmaprp_remove,
+ .driver = {
+ .name = MEM2MEM_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static void __exit emmaprp_exit(void)
+{
+ platform_driver_unregister(&emmaprp_pdrv);
+}
+
+static int __init emmaprp_init(void)
+{
+ return platform_driver_register(&emmaprp_pdrv);
+}
+
+module_init(emmaprp_init);
+module_exit(emmaprp_exit);
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index f96f92f00f92..93c35ef5f0ad 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -286,8 +286,8 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0);
sg_dma_len(sg) = new_size;
- txd = ichan->dma_chan.device->device_prep_slave_sg(
- &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE,
+ txd = dmaengine_prep_slave_sg(
+ &ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!txd)
goto error;
@@ -982,12 +982,13 @@ static int mx3_camera_querycap(struct soc_camera_host *ici,
return 0;
}
-static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static int mx3_camera_set_bus_param(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+ u32 pixfmt = icd->current_fmt->host_fmt->fourcc;
unsigned long bus_flags, common_flags;
u32 dw, sens_conf;
const struct soc_mbus_pixelfmt *fmt;
@@ -1285,19 +1286,7 @@ static struct platform_driver mx3_camera_driver = {
.remove = __devexit_p(mx3_camera_remove),
};
-
-static int __init mx3_camera_init(void)
-{
- return platform_driver_register(&mx3_camera_driver);
-}
-
-static void __exit mx3_camera_exit(void)
-{
- platform_driver_unregister(&mx3_camera_driver);
-}
-
-module_init(mx3_camera_init);
-module_exit(mx3_camera_exit);
+module_platform_driver(mx3_camera_driver);
MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/video/noon010pc30.c
index 50838bf84204..440c12962bae 100644
--- a/drivers/media/video/noon010pc30.c
+++ b/drivers/media/video/noon010pc30.c
@@ -725,8 +725,8 @@ static int noon010_probe(struct i2c_client *client,
mutex_init(&info->lock);
sd = &info->sd;
- strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
v4l2_i2c_subdev_init(sd, client, &noon010_ops);
+ strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
sd->internal_ops = &noon010_subdev_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -844,18 +844,7 @@ static struct i2c_driver noon010_i2c_driver = {
.id_table = noon010_id,
};
-static int __init noon010_init(void)
-{
- return i2c_add_driver(&noon010_i2c_driver);
-}
-
-static void __exit noon010_exit(void)
-{
- i2c_del_driver(&noon010_i2c_driver);
-}
-
-module_init(noon010_init);
-module_exit(noon010_exit);
+module_i2c_driver(noon010_i2c_driver);
MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index ee0d0b39cd17..88cf9d952631 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -70,9 +70,9 @@ static u32 video1_numbuffers = 3;
static u32 video2_numbuffers = 3;
static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
-static u32 vid1_static_vrfb_alloc;
-static u32 vid2_static_vrfb_alloc;
-static int debug;
+static bool vid1_static_vrfb_alloc;
+static bool vid2_static_vrfb_alloc;
+static bool debug;
/* Module parameters */
module_param(video1_numbuffers, uint, S_IRUGO);
@@ -424,7 +424,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
"%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n"
"rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n"
"out_height=%d rotation_type=%d screen_width=%d\n",
- __func__, info.enabled, info.paddr, info.width, info.height,
+ __func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height,
info.color_mode, info.rotation, info.mirror, info.pos_x,
info.pos_y, info.out_width, info.out_height, info.rotation_type,
info.screen_width);
@@ -524,10 +524,50 @@ static int omapvid_apply_changes(struct omap_vout_device *vout)
return 0;
}
+static int omapvid_handle_interlace_display(struct omap_vout_device *vout,
+ unsigned int irqstatus, struct timeval timevalue)
+{
+ u32 fid;
+
+ if (vout->first_int) {
+ vout->first_int = 0;
+ goto err;
+ }
+
+ if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
+ fid = 1;
+ else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
+ fid = 0;
+ else
+ goto err;
+
+ vout->field_id ^= 1;
+ if (fid != vout->field_id) {
+ if (fid == 0)
+ vout->field_id = fid;
+ } else if (0 == fid) {
+ if (vout->cur_frm == vout->next_frm)
+ goto err;
+
+ vout->cur_frm->ts = timevalue;
+ vout->cur_frm->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&vout->cur_frm->done);
+ vout->cur_frm = vout->next_frm;
+ } else {
+ if (list_empty(&vout->dma_queue) ||
+ (vout->cur_frm != vout->next_frm))
+ goto err;
+ }
+
+ return vout->field_id;
+err:
+ return 0;
+}
+
static void omap_vout_isr(void *arg, unsigned int irqstatus)
{
- int ret;
- u32 addr, fid;
+ int ret, fid, mgr_id;
+ u32 addr, irq;
struct omap_overlay *ovl;
struct timeval timevalue;
struct omapvideo_info *ovid;
@@ -543,112 +583,73 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus)
if (!ovl->manager || !ovl->manager->device)
return;
+ mgr_id = ovl->manager->id;
cur_display = ovl->manager->device;
spin_lock(&vout->vbq_lock);
do_gettimeofday(&timevalue);
- if (cur_display->type != OMAP_DISPLAY_TYPE_VENC) {
- switch (cur_display->type) {
- case OMAP_DISPLAY_TYPE_DPI:
- if (!(irqstatus & (DISPC_IRQ_VSYNC | DISPC_IRQ_VSYNC2)))
- goto vout_isr_err;
- break;
- case OMAP_DISPLAY_TYPE_HDMI:
- if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
- goto vout_isr_err;
- break;
- default:
- goto vout_isr_err;
- }
- if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
- vout->cur_frm->ts = timevalue;
- vout->cur_frm->state = VIDEOBUF_DONE;
- wake_up_interruptible(&vout->cur_frm->done);
- vout->cur_frm = vout->next_frm;
- }
- vout->first_int = 0;
- if (list_empty(&vout->dma_queue))
+ switch (cur_display->type) {
+ case OMAP_DISPLAY_TYPE_DSI:
+ case OMAP_DISPLAY_TYPE_DPI:
+ if (mgr_id == OMAP_DSS_CHANNEL_LCD)
+ irq = DISPC_IRQ_VSYNC;
+ else if (mgr_id == OMAP_DSS_CHANNEL_LCD2)
+ irq = DISPC_IRQ_VSYNC2;
+ else
goto vout_isr_err;
- vout->next_frm = list_entry(vout->dma_queue.next,
- struct videobuf_buffer, queue);
- list_del(&vout->next_frm->queue);
-
- vout->next_frm->state = VIDEOBUF_ACTIVE;
+ if (!(irqstatus & irq))
+ goto vout_isr_err;
+ break;
+ case OMAP_DISPLAY_TYPE_VENC:
+ fid = omapvid_handle_interlace_display(vout, irqstatus,
+ timevalue);
+ if (!fid)
+ goto vout_isr_err;
+ break;
+ case OMAP_DISPLAY_TYPE_HDMI:
+ if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
+ goto vout_isr_err;
+ break;
+ default:
+ goto vout_isr_err;
+ }
- addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
- + vout->cropped_offset;
+ if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
+ vout->cur_frm->ts = timevalue;
+ vout->cur_frm->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&vout->cur_frm->done);
+ vout->cur_frm = vout->next_frm;
+ }
- /* First save the configuration in ovelray structure */
- ret = omapvid_init(vout, addr);
- if (ret)
- printk(KERN_ERR VOUT_NAME
- "failed to set overlay info\n");
- /* Enable the pipeline and set the Go bit */
- ret = omapvid_apply_changes(vout);
- if (ret)
- printk(KERN_ERR VOUT_NAME "failed to change mode\n");
- } else {
+ vout->first_int = 0;
+ if (list_empty(&vout->dma_queue))
+ goto vout_isr_err;
- if (vout->first_int) {
- vout->first_int = 0;
- goto vout_isr_err;
- }
- if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
- fid = 1;
- else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
- fid = 0;
- else
- goto vout_isr_err;
+ vout->next_frm = list_entry(vout->dma_queue.next,
+ struct videobuf_buffer, queue);
+ list_del(&vout->next_frm->queue);
- vout->field_id ^= 1;
- if (fid != vout->field_id) {
- if (0 == fid)
- vout->field_id = fid;
+ vout->next_frm->state = VIDEOBUF_ACTIVE;
- goto vout_isr_err;
- }
- if (0 == fid) {
- if (vout->cur_frm == vout->next_frm)
- goto vout_isr_err;
-
- vout->cur_frm->ts = timevalue;
- vout->cur_frm->state = VIDEOBUF_DONE;
- wake_up_interruptible(&vout->cur_frm->done);
- vout->cur_frm = vout->next_frm;
- } else if (1 == fid) {
- if (list_empty(&vout->dma_queue) ||
- (vout->cur_frm != vout->next_frm))
- goto vout_isr_err;
-
- vout->next_frm = list_entry(vout->dma_queue.next,
- struct videobuf_buffer, queue);
- list_del(&vout->next_frm->queue);
-
- vout->next_frm->state = VIDEOBUF_ACTIVE;
- addr = (unsigned long)
- vout->queued_buf_addr[vout->next_frm->i] +
- vout->cropped_offset;
- /* First save the configuration in ovelray structure */
- ret = omapvid_init(vout, addr);
- if (ret)
- printk(KERN_ERR VOUT_NAME
- "failed to set overlay info\n");
- /* Enable the pipeline and set the Go bit */
- ret = omapvid_apply_changes(vout);
- if (ret)
- printk(KERN_ERR VOUT_NAME
- "failed to change mode\n");
- }
+ addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
+ + vout->cropped_offset;
- }
+ /* First save the configuration in ovelray structure */
+ ret = omapvid_init(vout, addr);
+ if (ret)
+ printk(KERN_ERR VOUT_NAME
+ "failed to set overlay info\n");
+ /* Enable the pipeline and set the Go bit */
+ ret = omapvid_apply_changes(vout);
+ if (ret)
+ printk(KERN_ERR VOUT_NAME "failed to change mode\n");
vout_isr_err:
spin_unlock(&vout->vbq_lock);
}
-
/* Video buffer call backs */
/*
@@ -664,10 +665,14 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
u32 phy_addr = 0, virt_addr = 0;
struct omap_vout_device *vout = q->priv_data;
struct omapvideo_info *ovid = &vout->vid_info;
+ int vid_max_buf_size;
if (!vout)
return -EINVAL;
+ vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize :
+ video2_bufsize;
+
if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
return -EINVAL;
@@ -690,7 +695,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
video1_numbuffers : video2_numbuffers;
/* Check the size of the buffer */
- if (*size > vout->buffer_size) {
+ if (*size > vid_max_buf_size) {
v4l2_err(&vout->vid_dev->v4l2_dev,
"buffer allocation mismatch [%u] [%u]\n",
*size, vout->buffer_size);
@@ -943,12 +948,8 @@ static int omap_vout_release(struct file *file)
/* Disable all the overlay managers connected with this interface */
for (i = 0; i < ovid->num_overlays; i++) {
struct omap_overlay *ovl = ovid->overlays[i];
- if (ovl->manager && ovl->manager->device) {
- struct omap_overlay_info info;
- ovl->get_overlay_info(ovl, &info);
- info.enabled = 0;
- ovl->set_overlay_info(ovl, &info);
- }
+ if (ovl->manager && ovl->manager->device)
+ ovl->disable(ovl);
}
/* Turn off the pipeline */
ret = omapvid_apply_changes(vout);
@@ -1041,7 +1042,8 @@ static int vidioc_querycap(struct file *file, void *fh,
strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
cap->bus_info[0] = '\0';
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
+ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
return 0;
}
@@ -1668,7 +1670,6 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
if (ovl->manager && ovl->manager->device) {
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
- info.enabled = 1;
info.paddr = addr;
if (ovl->set_overlay_info(ovl, &info)) {
ret = -EINVAL;
@@ -1687,6 +1688,16 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
if (ret)
v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
+ for (j = 0; j < ovid->num_overlays; j++) {
+ struct omap_overlay *ovl = ovid->overlays[j];
+
+ if (ovl->manager && ovl->manager->device) {
+ ret = ovl->enable(ovl);
+ if (ret)
+ goto streamon_err1;
+ }
+ }
+
ret = 0;
streamon_err1:
@@ -1716,16 +1727,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
for (j = 0; j < ovid->num_overlays; j++) {
struct omap_overlay *ovl = ovid->overlays[j];
- if (ovl->manager && ovl->manager->device) {
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
- info.enabled = 0;
- ret = ovl->set_overlay_info(ovl, &info);
- if (ret)
- v4l2_err(&vout->vid_dev->v4l2_dev,
- "failed to update overlay info in streamoff\n");
- }
+ if (ovl->manager && ovl->manager->device)
+ ovl->disable(ovl);
}
/* Turn of the pipeline */
@@ -1823,7 +1826,9 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
- a->flags = 0x0;
+ /* The video overlay must stay within the framebuffer and can't be
+ positioned independently. */
+ a->flags = V4L2_FBUF_FLAG_OVERLAY;
a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
| V4L2_FBUF_CAP_SRC_CHROMAKEY;
@@ -2263,13 +2268,12 @@ static struct platform_driver omap_vout_driver = {
.driver = {
.name = VOUT_NAME,
},
- .probe = omap_vout_probe,
.remove = omap_vout_remove,
};
static int __init omap_vout_init(void)
{
- if (platform_driver_register(&omap_vout_driver) != 0) {
+ if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) {
printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n");
return -EINVAL;
}
diff --git a/drivers/media/video/omap/omap_vout_vrfb.c b/drivers/media/video/omap/omap_vout_vrfb.c
index ebebcac49225..4be26abf6cea 100644
--- a/drivers/media/video/omap/omap_vout_vrfb.c
+++ b/drivers/media/video/omap/omap_vout_vrfb.c
@@ -84,7 +84,7 @@ void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
}
int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
- u32 static_vrfb_allocation)
+ bool static_vrfb_allocation)
{
int ret = 0, i, j;
struct omap_vout_device *vout;
diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h
index d793501cafcc..27a95d23b913 100644
--- a/drivers/media/video/omap/omap_voutdef.h
+++ b/drivers/media/video/omap/omap_voutdef.h
@@ -25,7 +25,7 @@
#define MAC_VRFB_CTXS 4
#define MAX_VOUT_DEV 2
#define MAX_OVLS 3
-#define MAX_DISPLAYS 3
+#define MAX_DISPLAYS 10
#define MAX_MANAGERS 3
#define QQVGA_WIDTH 160
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c
index 6a6cf388bae4..c20f5ecd6790 100644
--- a/drivers/media/video/omap1_camera.c
+++ b/drivers/media/video/omap1_camera.c
@@ -1436,13 +1436,13 @@ static int omap1_cam_querycap(struct soc_camera_host *ici,
return 0;
}
-static int omap1_cam_set_bus_param(struct soc_camera_device *icd,
- __u32 pixfmt)
+static int omap1_cam_set_bus_param(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->parent;
struct soc_camera_host *ici = to_soc_camera_host(dev);
struct omap1_cam_dev *pcdev = ici->priv;
+ u32 pixfmt = icd->current_fmt->host_fmt->fourcc;
const struct soc_camera_format_xlate *xlate;
const struct soc_mbus_pixelfmt *fmt;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
@@ -1713,17 +1713,7 @@ static struct platform_driver omap1_cam_driver = {
.remove = __exit_p(omap1_cam_remove),
};
-static int __init omap1_cam_init(void)
-{
- return platform_driver_register(&omap1_cam_driver);
-}
-module_init(omap1_cam_init);
-
-static void __exit omap1_cam_exit(void)
-{
- platform_driver_unregister(&omap1_cam_driver);
-}
-module_exit(omap1_cam_exit);
+module_platform_driver(omap1_cam_driver);
module_param(sg_mode, bool, 0644);
MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg");
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
index 45522e603185..7d3864144368 100644
--- a/drivers/media/video/omap24xxcam.c
+++ b/drivers/media/video/omap24xxcam.c
@@ -1868,21 +1868,7 @@ static struct platform_driver omap24xxcam_driver = {
},
};
-/*
- *
- * Module initialisation and deinitialisation
- *
- */
-
-static int __init omap24xxcam_init(void)
-{
- return platform_driver_register(&omap24xxcam_driver);
-}
-
-static void __exit omap24xxcam_cleanup(void)
-{
- platform_driver_unregister(&omap24xxcam_driver);
-}
+module_platform_driver(omap24xxcam_driver);
MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
@@ -1894,6 +1880,3 @@ MODULE_PARM_DESC(video_nr,
module_param(capture_mem, int, 0);
MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture "
"buffers (default 4800kiB)");
-
-module_init(omap24xxcam_init);
-module_exit(omap24xxcam_cleanup);
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
index d4c48ef227fb..12d5f923e1d0 100644
--- a/drivers/media/video/omap3isp/isp.c
+++ b/drivers/media/video/omap3isp/isp.c
@@ -403,6 +403,7 @@ static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus)
static void isp_isr_sbl(struct isp_device *isp)
{
struct device *dev = isp->dev;
+ struct isp_pipeline *pipe;
u32 sbl_pcr;
/*
@@ -416,27 +417,38 @@ static void isp_isr_sbl(struct isp_device *isp)
if (sbl_pcr)
dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr);
- if (sbl_pcr & (ISPSBL_PCR_CCDC_WBL_OVF | ISPSBL_PCR_CSIA_WBL_OVF
- | ISPSBL_PCR_CSIB_WBL_OVF)) {
- isp->isp_ccdc.error = 1;
- if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
- isp->isp_prev.error = 1;
- if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
- isp->isp_res.error = 1;
+ if (sbl_pcr & ISPSBL_PCR_CSIB_WBL_OVF) {
+ pipe = to_isp_pipeline(&isp->isp_ccp2.subdev.entity);
+ if (pipe != NULL)
+ pipe->error = true;
+ }
+
+ if (sbl_pcr & ISPSBL_PCR_CSIA_WBL_OVF) {
+ pipe = to_isp_pipeline(&isp->isp_csi2a.subdev.entity);
+ if (pipe != NULL)
+ pipe->error = true;
+ }
+
+ if (sbl_pcr & ISPSBL_PCR_CCDC_WBL_OVF) {
+ pipe = to_isp_pipeline(&isp->isp_ccdc.subdev.entity);
+ if (pipe != NULL)
+ pipe->error = true;
}
if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) {
- isp->isp_prev.error = 1;
- if (isp->isp_res.input == RESIZER_INPUT_VP &&
- !(isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER))
- isp->isp_res.error = 1;
+ pipe = to_isp_pipeline(&isp->isp_prev.subdev.entity);
+ if (pipe != NULL)
+ pipe->error = true;
}
if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF
| ISPSBL_PCR_RSZ2_WBL_OVF
| ISPSBL_PCR_RSZ3_WBL_OVF
- | ISPSBL_PCR_RSZ4_WBL_OVF))
- isp->isp_res.error = 1;
+ | ISPSBL_PCR_RSZ4_WBL_OVF)) {
+ pipe = to_isp_pipeline(&isp->isp_res.subdev.entity);
+ if (pipe != NULL)
+ pipe->error = true;
+ }
if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF)
omap3isp_stat_sbl_overflow(&isp->isp_af);
@@ -464,24 +476,17 @@ static irqreturn_t isp_isr(int irq, void *_isp)
IRQ0STATUS_HS_VS_IRQ;
struct isp_device *isp = _isp;
u32 irqstatus;
- int ret;
irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
isp_isr_sbl(isp);
- if (irqstatus & IRQ0STATUS_CSIA_IRQ) {
- ret = omap3isp_csi2_isr(&isp->isp_csi2a);
- if (ret)
- isp->isp_ccdc.error = 1;
- }
+ if (irqstatus & IRQ0STATUS_CSIA_IRQ)
+ omap3isp_csi2_isr(&isp->isp_csi2a);
- if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
- ret = omap3isp_ccp2_isr(&isp->isp_ccp2);
- if (ret)
- isp->isp_ccdc.error = 1;
- }
+ if (irqstatus & IRQ0STATUS_CSIB_IRQ)
+ omap3isp_ccp2_isr(&isp->isp_ccp2);
if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) {
if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
@@ -2222,24 +2227,7 @@ static struct platform_driver omap3isp_driver = {
},
};
-/*
- * isp_init - ISP module initialization.
- */
-static int __init isp_init(void)
-{
- return platform_driver_register(&omap3isp_driver);
-}
-
-/*
- * isp_cleanup - ISP module cleanup.
- */
-static void __exit isp_cleanup(void)
-{
- platform_driver_unregister(&omap3isp_driver);
-}
-
-module_init(isp_init);
-module_exit(isp_cleanup);
+module_platform_driver(omap3isp_driver);
MODULE_AUTHOR("Nokia Corporation");
MODULE_DESCRIPTION("TI OMAP3 ISP driver");
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
index d341ba12593f..eaabc27f0fa2 100644
--- a/drivers/media/video/omap3isp/ispccdc.c
+++ b/drivers/media/video/omap3isp/ispccdc.c
@@ -1406,8 +1406,7 @@ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)
{
- struct isp_pipeline *pipe =
- to_isp_pipeline(&ccdc->video_out.video.entity);
+ struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
struct video_device *vdev = ccdc->subdev.devnode;
struct v4l2_event event;
@@ -1428,8 +1427,11 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)
unsigned long flags;
if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) {
+ struct isp_pipeline *pipe =
+ to_isp_pipeline(&ccdc->subdev.entity);
+
ccdc_lsc_error_handler(ccdc);
- ccdc->error = 1;
+ pipe->error = true;
dev_dbg(to_device(ccdc), "lsc prefetch error\n");
}
@@ -1504,7 +1506,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
goto done;
}
- buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error);
+ buffer = omap3isp_video_buffer_next(&ccdc->video_out);
if (buffer != NULL) {
ccdc_set_outaddr(ccdc, buffer->isp_addr);
restart = 1;
@@ -1518,7 +1520,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
ISP_PIPELINE_STREAM_SINGLESHOT);
done:
- ccdc->error = 0;
return restart;
}
@@ -1744,7 +1745,6 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
*/
ccdc_config_vp(ccdc);
ccdc_enable_vp(ccdc, 1);
- ccdc->error = 0;
ccdc_print_status(ccdc);
}
diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h
index 483a19cac1ad..6d0264bab75b 100644
--- a/drivers/media/video/omap3isp/ispccdc.h
+++ b/drivers/media/video/omap3isp/ispccdc.h
@@ -150,7 +150,6 @@ struct ispccdc_lsc {
* @input: Active input
* @output: Active outputs
* @video_out: Output video node
- * @error: A hardware error occurred during capture
* @alaw: A-law compression enabled (1) or disabled (0)
* @lpf: Low pass filter enabled (1) or disabled (0)
* @obclamp: Optical-black clamp enabled (1) or disabled (0)
@@ -178,7 +177,6 @@ struct isp_ccdc_device {
enum ccdc_input_entity input;
unsigned int output;
struct isp_video video_out;
- unsigned int error;
unsigned int alaw:1,
lpf:1,
diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c
index 904ca8c8b17f..70ddbf35b223 100644
--- a/drivers/media/video/omap3isp/ispccp2.c
+++ b/drivers/media/video/omap3isp/ispccp2.c
@@ -556,7 +556,7 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
struct isp_buffer *buffer;
- buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error);
+ buffer = omap3isp_video_buffer_next(&ccp2->video_in);
if (buffer != NULL)
ccp2_set_inaddr(ccp2, buffer->isp_addr);
@@ -567,8 +567,6 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
omap3isp_pipeline_set_stream(pipe,
ISP_PIPELINE_STREAM_SINGLESHOT);
}
-
- ccp2->error = 0;
}
/*
@@ -576,13 +574,11 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
* @ccp2: Pointer to ISP CCP2 device
*
* This will handle the CCP2 interrupts
- *
- * Returns -EIO in case of error, or 0 on success.
*/
-int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
+void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
{
+ struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
struct isp_device *isp = to_isp_device(ccp2);
- int ret = 0;
static const u32 ISPCCP2_LC01_ERROR =
ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
@@ -604,19 +600,18 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
ISPCCP2_LCM_IRQSTATUS);
/* Errors */
if (lcx_irqstatus & ISPCCP2_LC01_ERROR) {
- ccp2->error = 1;
+ pipe->error = true;
dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus);
- return -EIO;
+ return;
}
if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) {
- ccp2->error = 1;
+ pipe->error = true;
dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus);
- ret = -EIO;
}
if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping))
- return 0;
+ return;
/* Frame number propagation */
if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) {
@@ -629,8 +624,6 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
/* Handle queued buffers on frame end interrupts */
if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ)
ccp2_isr_buffer(ccp2);
-
- return ret;
}
/* -----------------------------------------------------------------------------
@@ -867,7 +860,6 @@ static int ccp2_s_stream(struct v4l2_subdev *sd, int enable)
if (enable == ISP_PIPELINE_STREAM_STOPPED)
return 0;
atomic_set(&ccp2->stopping, 0);
- ccp2->error = 0;
}
switch (enable) {
diff --git a/drivers/media/video/omap3isp/ispccp2.h b/drivers/media/video/omap3isp/ispccp2.h
index 6674e9de2cd7..76d65f4576ef 100644
--- a/drivers/media/video/omap3isp/ispccp2.h
+++ b/drivers/media/video/omap3isp/ispccp2.h
@@ -82,7 +82,6 @@ struct isp_ccp2_device {
struct isp_video video_in;
struct isp_csiphy *phy;
struct regulator *vdds_csib;
- unsigned int error;
enum isp_pipeline_stream_state state;
wait_queue_head_t wait;
atomic_t stopping;
@@ -94,6 +93,6 @@ void omap3isp_ccp2_cleanup(struct isp_device *isp);
int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
struct v4l2_device *vdev);
void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2);
-int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);
+void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);
#endif /* OMAP3_ISP_CCP2_H */
diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c
index 0c5f1cb9d99d..fcb5168996a7 100644
--- a/drivers/media/video/omap3isp/ispcsi2.c
+++ b/drivers/media/video/omap3isp/ispcsi2.c
@@ -667,7 +667,7 @@ static void csi2_isr_buffer(struct isp_csi2_device *csi2)
csi2_ctx_enable(isp, csi2, 0, 0);
- buffer = omap3isp_video_buffer_next(&csi2->video_out, 0);
+ buffer = omap3isp_video_buffer_next(&csi2->video_out);
/*
* Let video queue operation restart engine if there is an underrun
@@ -727,17 +727,15 @@ static void csi2_isr_ctx(struct isp_csi2_device *csi2,
/*
* omap3isp_csi2_isr - CSI2 interrupt handling.
- *
- * Return -EIO on Transmission error
*/
-int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
+void omap3isp_csi2_isr(struct isp_csi2_device *csi2)
{
+ struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
u32 csi2_irqstatus, cpxio1_irqstatus;
struct isp_device *isp = csi2->isp;
- int retval = 0;
if (!csi2->available)
- return -ENODEV;
+ return;
csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS);
isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS);
@@ -750,7 +748,7 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ "
"%x\n", cpxio1_irqstatus);
- retval = -EIO;
+ pipe->error = true;
}
if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
@@ -775,11 +773,11 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0,
(csi2_irqstatus &
ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0);
- retval = -EIO;
+ pipe->error = true;
}
if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
- return 0;
+ return;
/* Successful cases */
if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0))
@@ -787,8 +785,6 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
dev_dbg(isp->dev, "CSI2: ECC correction done\n");
-
- return retval;
}
/* -----------------------------------------------------------------------------
diff --git a/drivers/media/video/omap3isp/ispcsi2.h b/drivers/media/video/omap3isp/ispcsi2.h
index 456fb7fb8a0f..885ad79a7678 100644
--- a/drivers/media/video/omap3isp/ispcsi2.h
+++ b/drivers/media/video/omap3isp/ispcsi2.h
@@ -156,7 +156,7 @@ struct isp_csi2_device {
atomic_t stopping;
};
-int omap3isp_csi2_isr(struct isp_csi2_device *csi2);
+void omap3isp_csi2_isr(struct isp_csi2_device *csi2);
int omap3isp_csi2_reset(struct isp_csi2_device *csi2);
int omap3isp_csi2_init(struct isp_device *isp);
void omap3isp_csi2_cleanup(struct isp_device *isp);
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c
index ccb876fe023f..6d0fb2c8c26d 100644
--- a/drivers/media/video/omap3isp/isppreview.c
+++ b/drivers/media/video/omap3isp/isppreview.c
@@ -116,11 +116,11 @@ static struct omap3isp_prev_csc flr_prev_csc = {
#define PREV_MIN_IN_HEIGHT 8
#define PREV_MAX_IN_HEIGHT 16384
-#define PREV_MIN_OUT_WIDTH 0
-#define PREV_MIN_OUT_HEIGHT 0
-#define PREV_MAX_OUT_WIDTH 1280
-#define PREV_MAX_OUT_WIDTH_ES2 3300
-#define PREV_MAX_OUT_WIDTH_3630 4096
+#define PREV_MIN_OUT_WIDTH 0
+#define PREV_MIN_OUT_HEIGHT 0
+#define PREV_MAX_OUT_WIDTH_REV_1 1280
+#define PREV_MAX_OUT_WIDTH_REV_2 3300
+#define PREV_MAX_OUT_WIDTH_REV_15 4096
/*
* Coeficient Tables for the submodules in Preview.
@@ -1306,14 +1306,14 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev)
switch (isp->revision) {
case ISP_REVISION_1_0:
- return PREV_MAX_OUT_WIDTH;
+ return PREV_MAX_OUT_WIDTH_REV_1;
case ISP_REVISION_2_0:
default:
- return PREV_MAX_OUT_WIDTH_ES2;
+ return PREV_MAX_OUT_WIDTH_REV_2;
case ISP_REVISION_15_0:
- return PREV_MAX_OUT_WIDTH_3630;
+ return PREV_MAX_OUT_WIDTH_REV_15;
}
}
@@ -1404,16 +1404,14 @@ static void preview_isr_buffer(struct isp_prev_device *prev)
int restart = 0;
if (prev->input == PREVIEW_INPUT_MEMORY) {
- buffer = omap3isp_video_buffer_next(&prev->video_in,
- prev->error);
+ buffer = omap3isp_video_buffer_next(&prev->video_in);
if (buffer != NULL)
preview_set_inaddr(prev, buffer->isp_addr);
pipe->state |= ISP_PIPELINE_IDLE_INPUT;
}
if (prev->output & PREVIEW_OUTPUT_MEMORY) {
- buffer = omap3isp_video_buffer_next(&prev->video_out,
- prev->error);
+ buffer = omap3isp_video_buffer_next(&prev->video_out);
if (buffer != NULL) {
preview_set_outaddr(prev, buffer->isp_addr);
restart = 1;
@@ -1440,8 +1438,6 @@ static void preview_isr_buffer(struct isp_prev_device *prev)
default:
return;
}
-
- prev->error = 0;
}
/*
@@ -1565,7 +1561,6 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable)
omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
preview_configure(prev);
atomic_set(&prev->stopping, 0);
- prev->error = 0;
preview_print_status(prev);
}
diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h
index f54e775c2df4..09686607973c 100644
--- a/drivers/media/video/omap3isp/isppreview.h
+++ b/drivers/media/video/omap3isp/isppreview.h
@@ -157,7 +157,6 @@ struct isptables_update {
* @output: Bitmask of the active output
* @video_in: Input video entity
* @video_out: Output video entity
- * @error: A hardware error occurred during capture
* @params: Module configuration data
* @shadow_update: If set, update the hardware configured in the next interrupt
* @underrun: Whether the preview entity has queued buffers on the output
@@ -179,7 +178,6 @@ struct isp_prev_device {
unsigned int output;
struct isp_video video_in;
struct isp_video video_out;
- unsigned int error;
struct prev_params params;
unsigned int shadow_update:1;
diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c
index 50e593bfcfaf..6958a9e3dc22 100644
--- a/drivers/media/video/omap3isp/ispresizer.c
+++ b/drivers/media/video/omap3isp/ispresizer.c
@@ -1038,7 +1038,7 @@ static void resizer_isr_buffer(struct isp_res_device *res)
/* Complete the output buffer and, if reading from memory, the input
* buffer.
*/
- buffer = omap3isp_video_buffer_next(&res->video_out, res->error);
+ buffer = omap3isp_video_buffer_next(&res->video_out);
if (buffer != NULL) {
resizer_set_outaddr(res, buffer->isp_addr);
restart = 1;
@@ -1047,7 +1047,7 @@ static void resizer_isr_buffer(struct isp_res_device *res)
pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
if (res->input == RESIZER_INPUT_MEMORY) {
- buffer = omap3isp_video_buffer_next(&res->video_in, 0);
+ buffer = omap3isp_video_buffer_next(&res->video_in);
if (buffer != NULL)
resizer_set_inaddr(res, buffer->isp_addr);
pipe->state |= ISP_PIPELINE_IDLE_INPUT;
@@ -1064,8 +1064,6 @@ static void resizer_isr_buffer(struct isp_res_device *res)
if (restart)
resizer_enable_oneshot(res);
}
-
- res->error = 0;
}
/*
@@ -1154,7 +1152,6 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
resizer_configure(res);
- res->error = 0;
resizer_print_status(res);
}
diff --git a/drivers/media/video/omap3isp/ispresizer.h b/drivers/media/video/omap3isp/ispresizer.h
index 76abc2e42126..70c1c0e1bbdf 100644
--- a/drivers/media/video/omap3isp/ispresizer.h
+++ b/drivers/media/video/omap3isp/ispresizer.h
@@ -107,7 +107,6 @@ struct isp_res_device {
enum resizer_input_entity input;
struct isp_video video_in;
struct isp_video video_out;
- unsigned int error;
u32 addr_base; /* stored source buffer address in memory mode */
u32 crop_offset; /* additional offset for crop in memory mode */
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c
index bd3aebafafa0..b02070057724 100644
--- a/drivers/media/video/omap3isp/ispvideo.c
+++ b/drivers/media/video/omap3isp/ispvideo.c
@@ -211,14 +211,14 @@ static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix,
mbus->width = pix->width;
mbus->height = pix->height;
- for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ /* Skip the last format in the loop so that it will be selected if no
+ * match is found.
+ */
+ for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
if (formats[i].pixelformat == pix->pixelformat)
break;
}
- if (WARN_ON(i == ARRAY_SIZE(formats)))
- return;
-
mbus->code = formats[i].code;
mbus->colorspace = pix->colorspace;
mbus->field = pix->field;
@@ -581,21 +581,20 @@ static const struct isp_video_queue_operations isp_video_queue_ops = {
/*
* omap3isp_video_buffer_next - Complete the current buffer and return the next
* @video: ISP video object
- * @error: Whether an error occurred during capture
*
* Remove the current video buffer from the DMA queue and fill its timestamp,
* field count and state fields before waking up its completion handler.
*
- * The buffer state is set to VIDEOBUF_DONE if no error occurred (@error is 0)
- * or VIDEOBUF_ERROR otherwise (@error is non-zero).
+ * For capture video nodes the buffer state is set to ISP_BUF_STATE_DONE if no
+ * error has been flagged in the pipeline, or to ISP_BUF_STATE_ERROR otherwise.
+ * For video output nodes the buffer state is always set to ISP_BUF_STATE_DONE.
*
* The DMA queue is expected to contain at least one buffer.
*
* Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
* empty.
*/
-struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
- unsigned int error)
+struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
{
struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
struct isp_video_queue *queue = video->queue;
@@ -630,7 +629,13 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
else
buf->vbuf.sequence = atomic_read(&pipe->frame_number);
- buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE;
+ /* Report pipeline errors to userspace on the capture device side. */
+ if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
+ buf->state = ISP_BUF_STATE_ERROR;
+ pipe->error = false;
+ } else {
+ buf->state = ISP_BUF_STATE_DONE;
+ }
wake_up(&buf->wait);
@@ -1016,6 +1021,8 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
if (ret < 0)
goto error;
+ pipe->error = false;
+
spin_lock_irqsave(&pipe->lock, flags);
pipe->state &= ~ISP_PIPELINE_STREAM;
pipe->state |= state;
diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h
index 08cbfa144e6e..d91bdb919be0 100644
--- a/drivers/media/video/omap3isp/ispvideo.h
+++ b/drivers/media/video/omap3isp/ispvideo.h
@@ -85,6 +85,10 @@ enum isp_pipeline_state {
ISP_PIPELINE_STREAM = 64,
};
+/*
+ * struct isp_pipeline - An ISP hardware pipeline
+ * @error: A hardware error occurred during capture
+ */
struct isp_pipeline {
struct media_pipeline pipe;
spinlock_t lock; /* Pipeline state and queue flags */
@@ -96,6 +100,7 @@ struct isp_pipeline {
unsigned int max_rate;
atomic_t frame_number;
bool do_propagation; /* of frame number */
+ bool error;
struct v4l2_fract max_timeperframe;
};
@@ -194,8 +199,7 @@ void omap3isp_video_cleanup(struct isp_video *video);
int omap3isp_video_register(struct isp_video *video,
struct v4l2_device *vdev);
void omap3isp_video_unregister(struct isp_video *video);
-struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
- unsigned int error);
+struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video);
void omap3isp_video_resume(struct isp_video *video, int continuous);
struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);
diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c
index b5247cb64fde..3c2c5d3bcc6b 100644
--- a/drivers/media/video/ov2640.c
+++ b/drivers/media/video/ov2640.c
@@ -1103,21 +1103,7 @@ static struct i2c_driver ov2640_i2c_driver = {
.id_table = ov2640_id,
};
-/*
- * Module functions
- */
-static int __init ov2640_module_init(void)
-{
- return i2c_add_driver(&ov2640_i2c_driver);
-}
-
-static void __exit ov2640_module_exit(void)
-{
- i2c_del_driver(&ov2640_i2c_driver);
-}
-
-module_init(ov2640_module_init);
-module_exit(ov2640_module_exit);
+module_i2c_driver(ov2640_i2c_driver);
MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor");
MODULE_AUTHOR("Alberto Panizzo");
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c
index bb37ec80f274..80e07794ac8e 100644
--- a/drivers/media/video/ov5642.c
+++ b/drivers/media/video/ov5642.c
@@ -1068,18 +1068,7 @@ static struct i2c_driver ov5642_i2c_driver = {
.id_table = ov5642_id,
};
-static int __init ov5642_mod_init(void)
-{
- return i2c_add_driver(&ov5642_i2c_driver);
-}
-
-static void __exit ov5642_mod_exit(void)
-{
- i2c_del_driver(&ov5642_i2c_driver);
-}
-
-module_init(ov5642_mod_init);
-module_exit(ov5642_mod_exit);
+module_i2c_driver(ov5642_i2c_driver);
MODULE_DESCRIPTION("Omnivision OV5642 Camera driver");
MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c
index 6806345ec2f0..3e028b1970dd 100644
--- a/drivers/media/video/ov6650.c
+++ b/drivers/media/video/ov6650.c
@@ -649,7 +649,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
clkrc = CLKRC_24MHz;
} else {
dev_err(&client->dev,
- "unspported input clock, check platform data\n");
+ "unsupported input clock, check platform data\n");
return -EINVAL;
}
mclk = sense->master_clock;
@@ -1046,18 +1046,7 @@ static struct i2c_driver ov6650_i2c_driver = {
.id_table = ov6650_id,
};
-static int __init ov6650_module_init(void)
-{
- return i2c_add_driver(&ov6650_i2c_driver);
-}
-
-static void __exit ov6650_module_exit(void)
-{
- i2c_del_driver(&ov6650_i2c_driver);
-}
-
-module_init(ov6650_module_init);
-module_exit(ov6650_module_exit);
+module_i2c_driver(ov6650_i2c_driver);
MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 8aa058531280..e7c82b297514 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -25,7 +25,7 @@ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
MODULE_LICENSE("GPL");
-static int debug;
+static bool debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -1583,15 +1583,4 @@ static struct i2c_driver ov7670_driver = {
.id_table = ov7670_id,
};
-static __init int init_ov7670(void)
-{
- return i2c_add_driver(&ov7670_driver);
-}
-
-static __exit void exit_ov7670(void)
-{
- i2c_del_driver(&ov7670_driver);
-}
-
-module_init(init_ov7670);
-module_exit(exit_ov7670);
+module_i2c_driver(ov7670_driver);
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 9f6ce3d8a29e..74e77d327ed8 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -1123,22 +1123,7 @@ static struct i2c_driver ov772x_i2c_driver = {
.id_table = ov772x_id,
};
-/*
- * module function
- */
-
-static int __init ov772x_module_init(void)
-{
- return i2c_add_driver(&ov772x_i2c_driver);
-}
-
-static void __exit ov772x_module_exit(void)
-{
- i2c_del_driver(&ov772x_i2c_driver);
-}
-
-module_init(ov772x_module_init);
-module_exit(ov772x_module_exit);
+module_i2c_driver(ov772x_i2c_driver);
MODULE_DESCRIPTION("SoC Camera driver for ov772x");
MODULE_AUTHOR("Kuninori Morimoto");
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index a4f99797eb56..23412debb36b 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -738,18 +738,7 @@ static struct i2c_driver ov9640_i2c_driver = {
.id_table = ov9640_id,
};
-static int __init ov9640_module_init(void)
-{
- return i2c_add_driver(&ov9640_i2c_driver);
-}
-
-static void __exit ov9640_module_exit(void)
-{
- i2c_del_driver(&ov9640_i2c_driver);
-}
-
-module_init(ov9640_module_init);
-module_exit(ov9640_module_exit);
+module_i2c_driver(ov9640_i2c_driver);
MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx");
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c
index d9a9f7174f7a..3eb07c22516e 100644
--- a/drivers/media/video/ov9740.c
+++ b/drivers/media/video/ov9740.c
@@ -998,18 +998,7 @@ static struct i2c_driver ov9740_i2c_driver = {
.id_table = ov9740_id,
};
-static int __init ov9740_module_init(void)
-{
- return i2c_add_driver(&ov9740_i2c_driver);
-}
-
-static void __exit ov9740_module_exit(void)
-{
- i2c_del_driver(&ov9740_i2c_driver);
-}
-
-module_init(ov9740_module_init);
-module_exit(ov9740_module_exit);
+module_i2c_driver(ov9740_i2c_driver);
MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740");
MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index c6da8f77e1a2..d8c898278e8c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -320,7 +320,17 @@ static struct tda829x_config tda829x_no_probe = {
.probe_tuner = TDA829X_DONT_PROBE,
};
+static struct tda18271_std_map hauppauge_tda18271_dvbt_std_map = {
+ .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+ .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+ .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
static struct tda18271_config hauppauge_tda18271_dvb_config = {
+ .std_map = &hauppauge_tda18271_dvbt_std_map,
.gate = TDA18271_GATE_ANALOG,
.output_opt = TDA18271_OUTPUT_LT_OFF,
};
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 122b45760f0d..ebc2c7e39233 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2546,8 +2546,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
}
/* Define and configure additional controls from cx2341x module. */
- hdw->mpeg_ctrl_info = kzalloc(
- sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
+ hdw->mpeg_ctrl_info = kcalloc(MPEGDEF_COUNT,
+ sizeof(*(hdw->mpeg_ctrl_info)),
+ GFP_KERNEL);
if (!hdw->mpeg_ctrl_info) goto fail;
for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
cptr = hdw->controls + idx + CTRLDEF_COUNT;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 6d666174dbb4..e1111d968a3d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -96,7 +96,6 @@ static struct v4l2_capability pvr_capability ={
.capabilities = (V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
V4L2_CAP_READWRITE),
- .reserved = {0,0,0,0}
};
static struct v4l2_fmtdesc pvr_fmtdesc [] = {
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 3977addf3ba8..1f506fde97d0 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -102,52 +102,18 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
#include "pwc-nala.h"
};
-static void pwc_set_image_buffer_size(struct pwc_device *pdev);
-
/****************************************************************************/
-static int _send_control_msg(struct pwc_device *pdev,
- u8 request, u16 value, int index, void *buf, int buflen)
-{
- int rc;
- void *kbuf = NULL;
-
- if (buflen) {
- kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */
- if (kbuf == NULL)
- return -ENOMEM;
- memcpy(kbuf, buf, buflen);
- }
-
- rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
- request,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- index,
- kbuf, buflen, USB_CTRL_SET_TIMEOUT);
-
- kfree(kbuf);
- return rc;
-}
-
static int recv_control_msg(struct pwc_device *pdev,
- u8 request, u16 value, void *buf, int buflen)
+ u8 request, u16 value, int recv_count)
{
int rc;
- void *kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */
-
- if (kbuf == NULL)
- return -ENOMEM;
rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
request,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- pdev->vcinterface,
- kbuf, buflen, USB_CTRL_GET_TIMEOUT);
- memcpy(buf, kbuf, buflen);
- kfree(kbuf);
-
+ value, pdev->vcinterface,
+ pdev->ctrl_buf, recv_count, USB_CTRL_GET_TIMEOUT);
if (rc < 0)
PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
rc, request, value);
@@ -155,26 +121,39 @@ static int recv_control_msg(struct pwc_device *pdev,
}
static inline int send_video_command(struct pwc_device *pdev,
- int index, void *buf, int buflen)
+ int index, const unsigned char *buf, int buflen)
{
- return _send_control_msg(pdev,
- SET_EP_STREAM_CTL,
- VIDEO_OUTPUT_CONTROL_FORMATTER,
- index,
- buf, buflen);
+ int rc;
+
+ memcpy(pdev->ctrl_buf, buf, buflen);
+
+ rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+ SET_EP_STREAM_CTL,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ VIDEO_OUTPUT_CONTROL_FORMATTER, index,
+ pdev->ctrl_buf, buflen, USB_CTRL_SET_TIMEOUT);
+ if (rc >= 0)
+ memcpy(pdev->cmd_buf, buf, buflen);
+ else
+ PWC_ERROR("send_video_command error %d\n", rc);
+
+ return rc;
}
int send_control_msg(struct pwc_device *pdev,
u8 request, u16 value, void *buf, int buflen)
{
- return _send_control_msg(pdev,
- request, value, pdev->vcinterface, buf, buflen);
+ return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+ request,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, pdev->vcinterface,
+ buf, buflen, USB_CTRL_SET_TIMEOUT);
}
-static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+static int set_video_mode_Nala(struct pwc_device *pdev, int size, int pixfmt,
+ int frames, int *compression, int send_to_cam)
{
- unsigned char buf[3];
- int ret, fps;
+ int fps, ret = 0;
struct Nala_table_entry *pEntry;
int frames2frames[31] =
{ /* closest match of framerate */
@@ -196,35 +175,34 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
7 /* 30 */
};
- if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
+ if (size < 0 || size > PSZ_CIF)
return -EINVAL;
+ if (frames < 4)
+ frames = 4;
+ else if (frames > 25)
+ frames = 25;
frames = frames2frames[frames];
fps = frames2table[frames];
pEntry = &Nala_table[size][fps];
if (pEntry->alternate == 0)
return -EINVAL;
- memcpy(buf, pEntry->mode, 3);
- ret = send_video_command(pdev, pdev->vendpoint, buf, 3);
- if (ret < 0) {
- PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
+ if (send_to_cam)
+ ret = send_video_command(pdev, pdev->vendpoint,
+ pEntry->mode, 3);
+ if (ret < 0)
return ret;
- }
- if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
- ret = pwc_dec1_init(pdev, pdev->type, pdev->release, buf);
- if (ret < 0)
- return ret;
- }
- pdev->cmd_len = 3;
- memcpy(pdev->cmd_buf, buf, 3);
+ if (pEntry->compressed && pixfmt == V4L2_PIX_FMT_YUV420)
+ pwc_dec1_init(pdev, pEntry->mode);
/* Set various parameters */
+ pdev->pixfmt = pixfmt;
pdev->vframes = frames;
- pdev->vsize = size;
pdev->valternate = pEntry->alternate;
- pdev->image = pwc_image_sizes[size];
- pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
+ pdev->width = pwc_image_sizes[size][0];
+ pdev->height = pwc_image_sizes[size][1];
+ pdev->frame_size = (pdev->width * pdev->height * 3) / 2;
if (pEntry->compressed) {
if (pdev->release < 5) { /* 4 fold compression */
pdev->vbandlength = 528;
@@ -237,183 +215,142 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
}
else
pdev->vbandlength = 0;
+
+ /* Let pwc-if.c:isoc_init know we don't support higher compression */
+ *compression = 3;
+
return 0;
}
-static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt,
+ int frames, int *compression, int send_to_cam)
{
- unsigned char buf[13];
const struct Timon_table_entry *pChoose;
- int ret, fps;
+ int fps, ret = 0;
- if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
- return -EINVAL;
- if (size == PSZ_VGA && frames > 15)
+ if (size >= PSZ_MAX || *compression < 0 || *compression > 3)
return -EINVAL;
+ if (frames < 5)
+ frames = 5;
+ else if (size == PSZ_VGA && frames > 15)
+ frames = 15;
+ else if (frames > 30)
+ frames = 30;
fps = (frames / 5) - 1;
- /* Find a supported framerate with progressively higher compression ratios
- if the preferred ratio is not available.
- */
+ /* Find a supported framerate with progressively higher compression */
pChoose = NULL;
- while (compression <= 3) {
- pChoose = &Timon_table[size][fps][compression];
- if (pChoose->alternate != 0)
- break;
- compression++;
+ while (*compression <= 3) {
+ pChoose = &Timon_table[size][fps][*compression];
+ if (pChoose->alternate != 0)
+ break;
+ (*compression)++;
}
if (pChoose == NULL || pChoose->alternate == 0)
return -ENOENT; /* Not supported. */
- memcpy(buf, pChoose->mode, 13);
- if (snapshot)
- buf[0] |= 0x80;
- ret = send_video_command(pdev, pdev->vendpoint, buf, 13);
+ if (send_to_cam)
+ ret = send_video_command(pdev, pdev->vendpoint,
+ pChoose->mode, 13);
if (ret < 0)
return ret;
- if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
- ret = pwc_dec23_init(pdev, pdev->type, buf);
- if (ret < 0)
- return ret;
- }
-
- pdev->cmd_len = 13;
- memcpy(pdev->cmd_buf, buf, 13);
+ if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420)
+ pwc_dec23_init(pdev, pChoose->mode);
/* Set various parameters */
- pdev->vframes = frames;
- pdev->vsize = size;
- pdev->vsnapshot = snapshot;
+ pdev->pixfmt = pixfmt;
+ pdev->vframes = (fps + 1) * 5;
pdev->valternate = pChoose->alternate;
- pdev->image = pwc_image_sizes[size];
+ pdev->width = pwc_image_sizes[size][0];
+ pdev->height = pwc_image_sizes[size][1];
pdev->vbandlength = pChoose->bandlength;
if (pChoose->bandlength > 0)
- pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
+ pdev->frame_size = (pChoose->bandlength * pdev->height) / 4;
else
- pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+ pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
return 0;
}
-static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt,
+ int frames, int *compression, int send_to_cam)
{
const struct Kiara_table_entry *pChoose = NULL;
- int fps, ret;
- unsigned char buf[12];
- struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}};
+ int fps, ret = 0;
- if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
- return -EINVAL;
- if (size == PSZ_VGA && frames > 15)
+ if (size >= PSZ_MAX || *compression < 0 || *compression > 3)
return -EINVAL;
+ if (frames < 5)
+ frames = 5;
+ else if (size == PSZ_VGA && frames > 15)
+ frames = 15;
+ else if (frames > 30)
+ frames = 30;
fps = (frames / 5) - 1;
- /* special case: VGA @ 5 fps and snapshot is raw bayer mode */
- if (size == PSZ_VGA && frames == 5 && snapshot && pdev->pixfmt != V4L2_PIX_FMT_YUV420)
- {
- /* Only available in case the raw palette is selected or
- we have the decompressor available. This mode is
- only available in compressed form
- */
- PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n");
- pChoose = &RawEntry;
- }
- else
- {
- /* Find a supported framerate with progressively higher compression ratios
- if the preferred ratio is not available.
- Skip this step when using RAW modes.
- */
- snapshot = 0;
- while (compression <= 3) {
- pChoose = &Kiara_table[size][fps][compression];
- if (pChoose->alternate != 0)
- break;
- compression++;
- }
+ /* Find a supported framerate with progressively higher compression */
+ while (*compression <= 3) {
+ pChoose = &Kiara_table[size][fps][*compression];
+ if (pChoose->alternate != 0)
+ break;
+ (*compression)++;
}
if (pChoose == NULL || pChoose->alternate == 0)
return -ENOENT; /* Not supported. */
- PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate);
-
- /* usb_control_msg won't take staticly allocated arrays as argument?? */
- memcpy(buf, pChoose->mode, 12);
- if (snapshot)
- buf[0] |= 0x80;
-
/* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
- ret = send_video_command(pdev, 4 /* pdev->vendpoint */, buf, 12);
+ if (send_to_cam)
+ ret = send_video_command(pdev, 4, pChoose->mode, 12);
if (ret < 0)
return ret;
- if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
- ret = pwc_dec23_init(pdev, pdev->type, buf);
- if (ret < 0)
- return ret;
- }
+ if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420)
+ pwc_dec23_init(pdev, pChoose->mode);
- pdev->cmd_len = 12;
- memcpy(pdev->cmd_buf, buf, 12);
/* All set and go */
- pdev->vframes = frames;
- pdev->vsize = size;
- pdev->vsnapshot = snapshot;
+ pdev->pixfmt = pixfmt;
+ pdev->vframes = (fps + 1) * 5;
pdev->valternate = pChoose->alternate;
- pdev->image = pwc_image_sizes[size];
+ pdev->width = pwc_image_sizes[size][0];
+ pdev->height = pwc_image_sizes[size][1];
pdev->vbandlength = pChoose->bandlength;
if (pdev->vbandlength > 0)
- pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
+ pdev->frame_size = (pdev->vbandlength * pdev->height) / 4;
else
- pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
- PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n",
- pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength);
+ pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
+ PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
+ pdev->frame_size, pdev->vframes, size, pdev->vbandlength);
return 0;
}
-
-
-/**
- @pdev: device structure
- @width: viewport width
- @height: viewport height
- @frame: framerate, in fps
- @compression: preferred compression ratio
- @snapshot: snapshot mode or streaming
- */
-int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
+int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
+ int pixfmt, int frames, int *compression, int send_to_cam)
{
int ret, size;
- PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt);
- size = pwc_decode_size(pdev, width, height);
- if (size < 0) {
- PWC_DEBUG_MODULE("Could not find suitable size.\n");
- return -ERANGE;
- }
+ PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n",
+ width, height, frames, pixfmt);
+ size = pwc_get_size(pdev, width, height);
PWC_TRACE("decode_size = %d.\n", size);
if (DEVICE_USE_CODEC1(pdev->type)) {
- ret = set_video_mode_Nala(pdev, size, frames);
-
+ ret = set_video_mode_Nala(pdev, size, pixfmt, frames,
+ compression, send_to_cam);
} else if (DEVICE_USE_CODEC3(pdev->type)) {
- ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
-
+ ret = set_video_mode_Kiara(pdev, size, pixfmt, frames,
+ compression, send_to_cam);
} else {
- ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
+ ret = set_video_mode_Timon(pdev, size, pixfmt, frames,
+ compression, send_to_cam);
}
if (ret < 0) {
PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
return ret;
}
- pdev->view.x = width;
- pdev->view.y = height;
- pdev->vcompression = compression;
pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
- pwc_set_image_buffer_size(pdev);
- PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
+ PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height);
return 0;
}
@@ -470,44 +407,15 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i
return ret;
}
-static void pwc_set_image_buffer_size(struct pwc_device *pdev)
-{
- int factor = 0;
-
- /* for V4L2_PIX_FMT_YUV420 */
- switch (pdev->pixfmt) {
- case V4L2_PIX_FMT_YUV420:
- factor = 6;
- break;
- case V4L2_PIX_FMT_PWC1:
- case V4L2_PIX_FMT_PWC2:
- factor = 6; /* can be uncompressed YUV420P */
- break;
- }
-
- /* Set sizes in bytes */
- pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
- pdev->view.size = pdev->view.x * pdev->view.y * factor / 4;
-
- /* Align offset, or you'll get some very weird results in
- YUV420 mode... x must be multiple of 4 (to get the Y's in
- place), and y even (or you'll mixup U & V). This is less of a
- problem for YUV420P.
- */
- pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
- pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
-}
-
int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
{
int ret;
- u8 buf;
- ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf));
+ ret = recv_control_msg(pdev, request, value, 1);
if (ret < 0)
return ret;
- *data = buf;
+ *data = pdev->ctrl_buf[0];
return 0;
}
@@ -515,7 +423,8 @@ int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
{
int ret;
- ret = send_control_msg(pdev, request, value, &data, sizeof(data));
+ pdev->ctrl_buf[0] = data;
+ ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1);
if (ret < 0)
return ret;
@@ -525,37 +434,34 @@ int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
{
int ret;
- s8 buf;
- ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf));
+ ret = recv_control_msg(pdev, request, value, 1);
if (ret < 0)
return ret;
- *data = buf;
+ *data = ((s8 *)pdev->ctrl_buf)[0];
return 0;
}
int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
{
int ret;
- u8 buf[2];
- ret = recv_control_msg(pdev, request, value, buf, sizeof(buf));
+ ret = recv_control_msg(pdev, request, value, 2);
if (ret < 0)
return ret;
- *data = (buf[1] << 8) | buf[0];
+ *data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0];
return 0;
}
int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data)
{
int ret;
- u8 buf[2];
- buf[0] = data & 0xff;
- buf[1] = data >> 8;
- ret = send_control_msg(pdev, request, value, buf, sizeof(buf));
+ pdev->ctrl_buf[0] = data & 0xff;
+ pdev->ctrl_buf[1] = data >> 8;
+ ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 2);
if (ret < 0)
return ret;
@@ -576,7 +482,6 @@ int pwc_button_ctrl(struct pwc_device *pdev, u16 value)
/* POWER */
void pwc_camera_power(struct pwc_device *pdev, int power)
{
- char buf;
int r;
if (!pdev->power_save)
@@ -586,69 +491,18 @@ void pwc_camera_power(struct pwc_device *pdev, int power)
return; /* Not supported by Nala or Timon < release 6 */
if (power)
- buf = 0x00; /* active */
+ pdev->ctrl_buf[0] = 0x00; /* active */
else
- buf = 0xFF; /* power save */
- r = send_control_msg(pdev,
- SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER,
- &buf, sizeof(buf));
-
+ pdev->ctrl_buf[0] = 0xFF; /* power save */
+ r = send_control_msg(pdev, SET_STATUS_CTL,
+ SET_POWER_SAVE_MODE_FORMATTER, pdev->ctrl_buf, 1);
if (r < 0)
PWC_ERROR("Failed to power %s camera (%d)\n",
power ? "on" : "off", r);
}
-static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
-{
- unsigned char buf;
-
- /* useful range is 0x01..0x20 */
- buf = speed / 0x7f0;
- return send_control_msg(pdev,
- SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf));
-}
-
-static int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
-{
- unsigned char buf;
- int ret;
-
- ret = recv_control_msg(pdev,
- GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf));
- if (ret < 0)
- return ret;
- *value = buf * 0x7f0;
- return 0;
-}
-
-
-static int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
-{
- unsigned char buf;
-
- /* useful range is 0x01..0x3F */
- buf = (delay >> 10);
- return send_control_msg(pdev,
- SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf));
-}
-
-static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
-{
- unsigned char buf;
- int ret;
-
- ret = recv_control_msg(pdev,
- GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf));
- if (ret < 0)
- return ret;
- *value = buf << 10;
- return 0;
-}
-
-
int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
{
- unsigned char buf[2];
int r;
if (pdev->type < 730)
@@ -664,123 +518,20 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
if (off_value > 0xff)
off_value = 0xff;
- buf[0] = on_value;
- buf[1] = off_value;
+ pdev->ctrl_buf[0] = on_value;
+ pdev->ctrl_buf[1] = off_value;
r = send_control_msg(pdev,
- SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf));
+ SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2);
if (r < 0)
PWC_ERROR("Failed to set LED on/off time (%d)\n", r);
return r;
}
-static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
-{
- unsigned char buf[2];
- int ret;
-
- if (pdev->type < 730) {
- *on_value = -1;
- *off_value = -1;
- return 0;
- }
-
- ret = recv_control_msg(pdev,
- GET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf));
- if (ret < 0)
- return ret;
- *on_value = buf[0] * 100;
- *off_value = buf[1] * 100;
- return 0;
-}
-
-static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
-{
- unsigned char buf;
-
- buf = flags & 0x03; // only lower two bits are currently used
- return send_control_msg(pdev,
- SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, &buf, sizeof(buf));
-}
-
-int pwc_mpt_reset(struct pwc_device *pdev, int flags)
-{
- int ret;
- ret = _pwc_mpt_reset(pdev, flags);
- if (ret >= 0) {
- pdev->pan_angle = 0;
- pdev->tilt_angle = 0;
- }
- return ret;
-}
-
-static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
-{
- unsigned char buf[4];
-
- /* set new relative angle; angles are expressed in degrees * 100,
- but cam as .5 degree resolution, hence divide by 200. Also
- the angle must be multiplied by 64 before it's send to
- the cam (??)
- */
- pan = 64 * pan / 100;
- tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */
- buf[0] = pan & 0xFF;
- buf[1] = (pan >> 8) & 0xFF;
- buf[2] = tilt & 0xFF;
- buf[3] = (tilt >> 8) & 0xFF;
- return send_control_msg(pdev,
- SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, &buf, sizeof(buf));
-}
-
-int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
-{
- int ret;
-
- /* check absolute ranges */
- if (pan < pdev->angle_range.pan_min ||
- pan > pdev->angle_range.pan_max ||
- tilt < pdev->angle_range.tilt_min ||
- tilt > pdev->angle_range.tilt_max)
- return -ERANGE;
-
- /* go to relative range, check again */
- pan -= pdev->pan_angle;
- tilt -= pdev->tilt_angle;
- /* angles are specified in degrees * 100, thus the limit = 36000 */
- if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000)
- return -ERANGE;
-
- ret = _pwc_mpt_set_angle(pdev, pan, tilt);
- if (ret >= 0) {
- pdev->pan_angle += pan;
- pdev->tilt_angle += tilt;
- }
- if (ret == -EPIPE) /* stall -> out of range */
- ret = -ERANGE;
- return ret;
-}
-
-static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
-{
- int ret;
- unsigned char buf[5];
-
- ret = recv_control_msg(pdev,
- GET_MPT_CTL, PT_STATUS_FORMATTER, &buf, sizeof(buf));
- if (ret < 0)
- return ret;
- status->status = buf[0] & 0x7; // 3 bits are used for reporting
- status->time_pan = (buf[1] << 8) + buf[2];
- status->time_tilt = (buf[3] << 8) + buf[4];
- return 0;
-}
-
#ifdef CONFIG_USB_PWC_DEBUG
int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
{
- unsigned char buf;
int ret = -1, request;
if (pdev->type < 675)
@@ -790,431 +541,13 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
else
request = SENSOR_TYPE_FORMATTER2;
- ret = recv_control_msg(pdev,
- GET_STATUS_CTL, request, &buf, sizeof(buf));
+ ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1);
if (ret < 0)
return ret;
if (pdev->type < 675)
- *sensor = buf | 0x100;
+ *sensor = pdev->ctrl_buf[0] | 0x100;
else
- *sensor = buf;
+ *sensor = pdev->ctrl_buf[0];
return 0;
}
#endif
-
- /* End of Add-Ons */
- /* ************************************************* */
-
-/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
- ioctl() calls. With 2.4, you have to do tedious copy_from_user()
- and copy_to_user() calls. With these macros we circumvent this,
- and let me maintain only one source file. The functionality is
- exactly the same otherwise.
- */
-
-/* define local variable for arg */
-#define ARG_DEF(ARG_type, ARG_name)\
- ARG_type *ARG_name = arg;
-/* copy arg to local variable */
-#define ARG_IN(ARG_name) /* nothing */
-/* argument itself (referenced) */
-#define ARGR(ARG_name) (*ARG_name)
-/* argument address */
-#define ARGA(ARG_name) ARG_name
-/* copy local variable to arg */
-#define ARG_OUT(ARG_name) /* nothing */
-
-/*
- * Our ctrls use native values, but the old custom pwc ioctl interface expects
- * values from 0 - 65535, define 2 helper functions to scale things. */
-static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl)
-{
- return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum;
-}
-
-static int pwc_ioctl_s_ctrl(struct v4l2_ctrl *ctrl, int val)
-{
- return v4l2_ctrl_s_ctrl(ctrl, val * ctrl->maximum / 65535);
-}
-
-long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
-{
- long ret = 0;
-
- switch(cmd) {
- case VIDIOCPWCRUSER:
- ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER);
- break;
-
- case VIDIOCPWCSUSER:
- ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER);
- break;
-
- case VIDIOCPWCFACTORY:
- ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER);
- break;
-
- case VIDIOCPWCSCQUAL:
- {
- ARG_DEF(int, qual)
-
- if (vb2_is_streaming(&pdev->vb_queue)) {
- ret = -EBUSY;
- break;
- }
-
- ARG_IN(qual)
- if (ARGR(qual) < 0 || ARGR(qual) > 3)
- ret = -EINVAL;
- else
- ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
- break;
- }
-
- case VIDIOCPWCGCQUAL:
- {
- ARG_DEF(int, qual)
-
- ARGR(qual) = pdev->vcompression;
- ARG_OUT(qual)
- break;
- }
-
- case VIDIOCPWCPROBE:
- {
- ARG_DEF(struct pwc_probe, probe)
-
- strcpy(ARGR(probe).name, pdev->vdev.name);
- ARGR(probe).type = pdev->type;
- ARG_OUT(probe)
- break;
- }
-
- case VIDIOCPWCGSERIAL:
- {
- ARG_DEF(struct pwc_serial, serial)
-
- strcpy(ARGR(serial).serial, pdev->serial);
- ARG_OUT(serial)
- break;
- }
-
- case VIDIOCPWCSAGC:
- {
- ARG_DEF(int, agc)
- ARG_IN(agc)
- ret = v4l2_ctrl_s_ctrl(pdev->autogain, ARGR(agc) < 0);
- if (ret == 0 && ARGR(agc) >= 0)
- ret = pwc_ioctl_s_ctrl(pdev->gain, ARGR(agc));
- break;
- }
-
- case VIDIOCPWCGAGC:
- {
- ARG_DEF(int, agc)
- if (v4l2_ctrl_g_ctrl(pdev->autogain))
- ARGR(agc) = -1;
- else
- ARGR(agc) = pwc_ioctl_g_ctrl(pdev->gain);
- ARG_OUT(agc)
- break;
- }
-
- case VIDIOCPWCSSHUTTER:
- {
- ARG_DEF(int, shutter)
- ARG_IN(shutter)
- ret = v4l2_ctrl_s_ctrl(pdev->exposure_auto,
- /* Menu idx 0 = auto, idx 1 = manual */
- ARGR(shutter) >= 0);
- if (ret == 0 && ARGR(shutter) >= 0)
- ret = pwc_ioctl_s_ctrl(pdev->exposure, ARGR(shutter));
- break;
- }
-
- case VIDIOCPWCSAWB:
- {
- ARG_DEF(struct pwc_whitebalance, wb)
- ARG_IN(wb)
- ret = v4l2_ctrl_s_ctrl(pdev->auto_white_balance,
- ARGR(wb).mode);
- if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL)
- ret = pwc_ioctl_s_ctrl(pdev->red_balance,
- ARGR(wb).manual_red);
- if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL)
- ret = pwc_ioctl_s_ctrl(pdev->blue_balance,
- ARGR(wb).manual_blue);
- break;
- }
-
- case VIDIOCPWCGAWB:
- {
- ARG_DEF(struct pwc_whitebalance, wb)
- ARGR(wb).mode = v4l2_ctrl_g_ctrl(pdev->auto_white_balance);
- ARGR(wb).manual_red = ARGR(wb).read_red =
- pwc_ioctl_g_ctrl(pdev->red_balance);
- ARGR(wb).manual_blue = ARGR(wb).read_blue =
- pwc_ioctl_g_ctrl(pdev->blue_balance);
- ARG_OUT(wb)
- break;
- }
-
- case VIDIOCPWCSAWBSPEED:
- {
- ARG_DEF(struct pwc_wb_speed, wbs)
-
- if (ARGR(wbs).control_speed > 0) {
- ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
- }
- if (ARGR(wbs).control_delay > 0) {
- ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
- }
- break;
- }
-
- case VIDIOCPWCGAWBSPEED:
- {
- ARG_DEF(struct pwc_wb_speed, wbs)
-
- ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
- if (ret < 0)
- break;
- ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
- if (ret < 0)
- break;
- ARG_OUT(wbs)
- break;
- }
-
- case VIDIOCPWCSLED:
- {
- ARG_DEF(struct pwc_leds, leds)
-
- ARG_IN(leds)
- ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
- break;
- }
-
-
- case VIDIOCPWCGLED:
- {
- ARG_DEF(struct pwc_leds, leds)
-
- ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
- ARG_OUT(leds)
- break;
- }
-
- case VIDIOCPWCSCONTOUR:
- {
- ARG_DEF(int, contour)
- ARG_IN(contour)
- ret = v4l2_ctrl_s_ctrl(pdev->autocontour, ARGR(contour) < 0);
- if (ret == 0 && ARGR(contour) >= 0)
- ret = pwc_ioctl_s_ctrl(pdev->contour, ARGR(contour));
- break;
- }
-
- case VIDIOCPWCGCONTOUR:
- {
- ARG_DEF(int, contour)
- if (v4l2_ctrl_g_ctrl(pdev->autocontour))
- ARGR(contour) = -1;
- else
- ARGR(contour) = pwc_ioctl_g_ctrl(pdev->contour);
- ARG_OUT(contour)
- break;
- }
-
- case VIDIOCPWCSBACKLIGHT:
- {
- ARG_DEF(int, backlight)
- ARG_IN(backlight)
- ret = v4l2_ctrl_s_ctrl(pdev->backlight, ARGR(backlight));
- break;
- }
-
- case VIDIOCPWCGBACKLIGHT:
- {
- ARG_DEF(int, backlight)
- ARGR(backlight) = v4l2_ctrl_g_ctrl(pdev->backlight);
- ARG_OUT(backlight)
- break;
- }
-
- case VIDIOCPWCSFLICKER:
- {
- ARG_DEF(int, flicker)
- ARG_IN(flicker)
- ret = v4l2_ctrl_s_ctrl(pdev->flicker, ARGR(flicker));
- break;
- }
-
- case VIDIOCPWCGFLICKER:
- {
- ARG_DEF(int, flicker)
- ARGR(flicker) = v4l2_ctrl_g_ctrl(pdev->flicker);
- ARG_OUT(flicker)
- break;
- }
-
- case VIDIOCPWCSDYNNOISE:
- {
- ARG_DEF(int, dynnoise)
- ARG_IN(dynnoise)
- ret = v4l2_ctrl_s_ctrl(pdev->noise_reduction, ARGR(dynnoise));
- break;
- }
-
- case VIDIOCPWCGDYNNOISE:
- {
- ARG_DEF(int, dynnoise)
- ARGR(dynnoise) = v4l2_ctrl_g_ctrl(pdev->noise_reduction);
- ARG_OUT(dynnoise);
- break;
- }
-
- case VIDIOCPWCGREALSIZE:
- {
- ARG_DEF(struct pwc_imagesize, size)
-
- ARGR(size).width = pdev->image.x;
- ARGR(size).height = pdev->image.y;
- ARG_OUT(size)
- break;
- }
-
- case VIDIOCPWCMPTRESET:
- {
- if (pdev->features & FEATURE_MOTOR_PANTILT)
- {
- ARG_DEF(int, flags)
-
- ARG_IN(flags)
- ret = pwc_mpt_reset(pdev, ARGR(flags));
- }
- else
- {
- ret = -ENXIO;
- }
- break;
- }
-
- case VIDIOCPWCMPTGRANGE:
- {
- if (pdev->features & FEATURE_MOTOR_PANTILT)
- {
- ARG_DEF(struct pwc_mpt_range, range)
-
- ARGR(range) = pdev->angle_range;
- ARG_OUT(range)
- }
- else
- {
- ret = -ENXIO;
- }
- break;
- }
-
- case VIDIOCPWCMPTSANGLE:
- {
- int new_pan, new_tilt;
-
- if (pdev->features & FEATURE_MOTOR_PANTILT)
- {
- ARG_DEF(struct pwc_mpt_angles, angles)
-
- ARG_IN(angles)
- /* The camera can only set relative angles, so
- do some calculations when getting an absolute angle .
- */
- if (ARGR(angles).absolute)
- {
- new_pan = ARGR(angles).pan;
- new_tilt = ARGR(angles).tilt;
- }
- else
- {
- new_pan = pdev->pan_angle + ARGR(angles).pan;
- new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
- }
- ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
- }
- else
- {
- ret = -ENXIO;
- }
- break;
- }
-
- case VIDIOCPWCMPTGANGLE:
- {
-
- if (pdev->features & FEATURE_MOTOR_PANTILT)
- {
- ARG_DEF(struct pwc_mpt_angles, angles)
-
- ARGR(angles).absolute = 1;
- ARGR(angles).pan = pdev->pan_angle;
- ARGR(angles).tilt = pdev->tilt_angle;
- ARG_OUT(angles)
- }
- else
- {
- ret = -ENXIO;
- }
- break;
- }
-
- case VIDIOCPWCMPTSTATUS:
- {
- if (pdev->features & FEATURE_MOTOR_PANTILT)
- {
- ARG_DEF(struct pwc_mpt_status, status)
-
- ret = pwc_mpt_get_status(pdev, ARGA(status));
- ARG_OUT(status)
- }
- else
- {
- ret = -ENXIO;
- }
- break;
- }
-
- case VIDIOCPWCGVIDCMD:
- {
- ARG_DEF(struct pwc_video_command, vcmd);
-
- ARGR(vcmd).type = pdev->type;
- ARGR(vcmd).release = pdev->release;
- ARGR(vcmd).command_len = pdev->cmd_len;
- memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
- ARGR(vcmd).bandlength = pdev->vbandlength;
- ARGR(vcmd).frame_size = pdev->frame_size;
- ARG_OUT(vcmd)
- break;
- }
- /*
- case VIDIOCPWCGVIDTABLE:
- {
- ARG_DEF(struct pwc_table_init_buffer, table);
- ARGR(table).len = pdev->cmd_len;
- memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
- ARG_OUT(table)
- break;
- }
- */
-
- default:
- ret = -ENOIOCTLCMD;
- break;
- }
-
- if (ret > 0)
- return 0;
- return ret;
-}
-
-
-/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-dec1.c b/drivers/media/video/pwc/pwc-dec1.c
index be0e02cb487f..e899036aadf4 100644
--- a/drivers/media/video/pwc/pwc-dec1.c
+++ b/drivers/media/video/pwc/pwc-dec1.c
@@ -22,19 +22,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "pwc-dec1.h"
+#include "pwc.h"
-int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer)
+void pwc_dec1_init(struct pwc_device *pdev, const unsigned char *cmd)
{
- struct pwc_dec1_private *pdec;
+ struct pwc_dec1_private *pdec = &pdev->dec1;
- if (pwc->decompress_data == NULL) {
- pdec = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
- if (pdec == NULL)
- return -ENOMEM;
- pwc->decompress_data = pdec;
- }
- pdec = pwc->decompress_data;
-
- return 0;
+ pdec->version = pdev->release;
}
diff --git a/drivers/media/video/pwc/pwc-dec1.h b/drivers/media/video/pwc/pwc-dec1.h
index a57d8601080b..c565ef8f52fb 100644
--- a/drivers/media/video/pwc/pwc-dec1.h
+++ b/drivers/media/video/pwc/pwc-dec1.h
@@ -25,13 +25,15 @@
#ifndef PWC_DEC1_H
#define PWC_DEC1_H
-#include "pwc.h"
+#include <linux/mutex.h>
+
+struct pwc_device;
struct pwc_dec1_private
{
int version;
};
-int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer);
+void pwc_dec1_init(struct pwc_device *pdev, const unsigned char *cmd);
#endif
diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c
index 06a4e877ba40..3792fedff951 100644
--- a/drivers/media/video/pwc/pwc-dec23.c
+++ b/drivers/media/video/pwc/pwc-dec23.c
@@ -27,7 +27,6 @@
#include "pwc-timon.h"
#include "pwc-kiara.h"
#include "pwc-dec23.h"
-#include <media/pwc-ioctl.h>
#include <linux/string.h>
#include <linux/slab.h>
@@ -51,13 +50,6 @@
# define USE_LOOKUP_TABLE_TO_CLAMP 1
#endif
-/*
- * ENABLE_BAYER_DECODER
- * 0: bayer decoder is not build (save some space)
- * 1: bayer decoder is build and can be used
- */
-#define ENABLE_BAYER_DECODER 0
-
static void build_subblock_pattern(struct pwc_dec23_private *pdec)
{
static const unsigned int initial_values[12] = {
@@ -302,20 +294,17 @@ static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE];
/* If the type or the command change, we rebuild the lookup table */
-int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd)
+void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd)
{
int flags, version, shift, i;
- struct pwc_dec23_private *pdec;
+ struct pwc_dec23_private *pdec = &pdev->dec23;
- if (pwc->decompress_data == NULL) {
- pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
- if (pdec == NULL)
- return -ENOMEM;
- pwc->decompress_data = pdec;
- }
- pdec = pwc->decompress_data;
+ mutex_init(&pdec->lock);
- if (DEVICE_USE_CODEC3(type)) {
+ if (pdec->last_cmd_valid && pdec->last_cmd == cmd[2])
+ return;
+
+ if (DEVICE_USE_CODEC3(pdev->type)) {
flags = cmd[2] & 0x18;
if (flags == 8)
pdec->nbits = 7; /* More bits, mean more bits to encode the stream, but better quality */
@@ -362,7 +351,8 @@ int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd)
pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255;
#endif
- return 0;
+ pdec->last_cmd = cmd[2];
+ pdec->last_cmd_valid = 1;
}
/*
@@ -467,123 +457,6 @@ static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned i
#endif
}
-#if ENABLE_BAYER_DECODER
-/*
- * Format: 8x2 pixels
- * . G . G . G . G . G . G . G
- * . . . . . . . . . . . . . .
- * . G . G . G . G . G . G . G
- * . . . . . . . . . . . . . .
- * or
- * . . . . . . . . . . . . . .
- * G . G . G . G . G . G . G .
- * . . . . . . . . . . . . . .
- * G . G . G . G . G . G . G .
-*/
-static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
-{
-#if UNROLL_LOOP_FOR_COPY
- /* Unroll all loops */
- const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
- unsigned char *d = dst;
- const int *c = src;
-
- d[0] = cm[c[0] >> scalebits];
- d[2] = cm[c[1] >> scalebits];
- d[4] = cm[c[2] >> scalebits];
- d[6] = cm[c[3] >> scalebits];
- d[8] = cm[c[4] >> scalebits];
- d[10] = cm[c[5] >> scalebits];
- d[12] = cm[c[6] >> scalebits];
- d[14] = cm[c[7] >> scalebits];
-
- d = dst + bytes_per_line;
- d[0] = cm[c[8] >> scalebits];
- d[2] = cm[c[9] >> scalebits];
- d[4] = cm[c[10] >> scalebits];
- d[6] = cm[c[11] >> scalebits];
- d[8] = cm[c[12] >> scalebits];
- d[10] = cm[c[13] >> scalebits];
- d[12] = cm[c[14] >> scalebits];
- d[14] = cm[c[15] >> scalebits];
-#else
- int i;
- unsigned char *d;
- const int *c = src;
-
- d = dst;
- for (i = 0; i < 8; i++, c++)
- d[i*2] = CLAMP((*c) >> scalebits);
-
- d = dst + bytes_per_line;
- for (i = 0; i < 8; i++, c++)
- d[i*2] = CLAMP((*c) >> scalebits);
-#endif
-}
-#endif
-
-#if ENABLE_BAYER_DECODER
-/*
- * Format: 4x4 pixels
- * R . R . R . R
- * . B . B . B .
- * R . R . R . R
- * . B . B . B .
- */
-static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
-{
-#if UNROLL_LOOP_FOR_COPY
- /* Unroll all loops */
- const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
- unsigned char *d = dst;
- const int *c = src;
-
- d[0] = cm[c[0] >> scalebits];
- d[2] = cm[c[1] >> scalebits];
- d[4] = cm[c[2] >> scalebits];
- d[6] = cm[c[3] >> scalebits];
-
- d = dst + bytes_per_line;
- d[1] = cm[c[4] >> scalebits];
- d[3] = cm[c[5] >> scalebits];
- d[5] = cm[c[6] >> scalebits];
- d[7] = cm[c[7] >> scalebits];
-
- d = dst + bytes_per_line*2;
- d[0] = cm[c[8] >> scalebits];
- d[2] = cm[c[9] >> scalebits];
- d[4] = cm[c[10] >> scalebits];
- d[6] = cm[c[11] >> scalebits];
-
- d = dst + bytes_per_line*3;
- d[1] = cm[c[12] >> scalebits];
- d[3] = cm[c[13] >> scalebits];
- d[5] = cm[c[14] >> scalebits];
- d[7] = cm[c[15] >> scalebits];
-#else
- int i;
- unsigned char *d;
- const int *c = src;
-
- d = dst;
- for (i = 0; i < 4; i++, c++)
- d[i*2] = CLAMP((*c) >> scalebits);
-
- d = dst + bytes_per_line;
- for (i = 0; i < 4; i++, c++)
- d[i*2+1] = CLAMP((*c) >> scalebits);
-
- d = dst + bytes_per_line*2;
- for (i = 0; i < 4; i++, c++)
- d[i*2] = CLAMP((*c) >> scalebits);
-
- d = dst + bytes_per_line*3;
- for (i = 0; i < 4; i++, c++)
- d[i*2+1] = CLAMP((*c) >> scalebits);
-#endif
-}
-#endif
-
/*
* To manage the stream, we keep bits in a 32 bits register.
* fill_nbits(n): fill the reservoir with at least n bits
@@ -775,146 +648,44 @@ static void DecompressBand23(struct pwc_dec23_private *pdec,
}
-#if ENABLE_BAYER_DECODER
-/*
- * Size need to be a multiple of 8 in width
- *
- * Return a block of four line encoded like this:
- *
- * G R G R G R G R G R G R G R G R
- * B G B G B G B G B G B G B G B G
- * G R G R G R G R G R G R G R G R
- * B G B G B G B G B G B G B G B G
- *
- */
-static void DecompressBandBayer(struct pwc_dec23_private *pdec,
- const unsigned char *rawyuv,
- unsigned char *rgbbayer,
- unsigned int compressed_image_width,
- unsigned int real_image_width)
-{
- int compression_index, nblocks;
- const unsigned char *ptable0004;
- const unsigned char *ptable8004;
- unsigned char *dest;
-
- pdec->reservoir = 0;
- pdec->nbits_in_reservoir = 0;
- pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */
-
- get_nbits(pdec, 4, compression_index);
-
- /* pass 1: uncompress RB component */
- nblocks = compressed_image_width / 4;
-
- ptable0004 = pdec->table_0004_pass1[compression_index];
- ptable8004 = pdec->table_8004_pass1[compression_index];
- dest = rgbbayer;
-
- /* Each block decode a square of 4x4 */
- while (nblocks) {
- decode_block(pdec, ptable0004, ptable8004);
- copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits);
- dest += 8;
- nblocks--;
- }
-
- /* pass 2: uncompress G component */
- nblocks = compressed_image_width / 8;
-
- ptable0004 = pdec->table_0004_pass2[compression_index];
- ptable8004 = pdec->table_8004_pass2[compression_index];
-
- /* Each block decode a square of 4x4 */
- while (nblocks) {
- decode_block(pdec, ptable0004, ptable8004);
- copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits);
-
- decode_block(pdec, ptable0004, ptable8004);
- copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits);
-
- rgbbayer += 16;
- nblocks -= 2;
- }
-}
-#endif
-
-
/**
*
* Uncompress a pwc23 buffer.
*
- * pwc.view: size of the image wanted
- * pwc.image: size of the image returned by the camera
- * pwc.offset: (x,y) to displayer image in the view
- *
* src: raw data
* dst: image output
- * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER
*/
-void pwc_dec23_decompress(const struct pwc_device *pwc,
+void pwc_dec23_decompress(struct pwc_device *pdev,
const void *src,
- void *dst,
- int flags)
+ void *dst)
{
- int bandlines_left, stride, bytes_per_block;
-
- bandlines_left = pwc->image.y / 4;
- bytes_per_block = pwc->view.x * 4;
-
- if (flags & PWCX_FLAG_BAYER) {
-#if ENABLE_BAYER_DECODER
- /* RGB Bayer format */
- unsigned char *rgbout;
-
- stride = pwc->view.x * pwc->offset.y;
- rgbout = dst + stride + pwc->offset.x;
-
-
- while (bandlines_left--) {
-
- DecompressBandBayer(pwc->decompress_data,
- src,
- rgbout,
- pwc->image.x, pwc->view.x);
-
- src += pwc->vbandlength;
- rgbout += bytes_per_block;
-
- }
-#else
- memset(dst, 0, pwc->view.x * pwc->view.y);
-#endif
-
- } else {
- /* YUV420P image format */
- unsigned char *pout_planar_y;
- unsigned char *pout_planar_u;
- unsigned char *pout_planar_v;
- unsigned int plane_size;
-
- plane_size = pwc->view.x * pwc->view.y;
-
- /* offset in Y plane */
- stride = pwc->view.x * pwc->offset.y;
- pout_planar_y = dst + stride + pwc->offset.x;
-
- /* offsets in U/V planes */
- stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2;
- pout_planar_u = dst + plane_size + stride;
- pout_planar_v = dst + plane_size + plane_size / 4 + stride;
-
- while (bandlines_left--) {
-
- DecompressBand23(pwc->decompress_data,
- src,
- pout_planar_y, pout_planar_u, pout_planar_v,
- pwc->image.x, pwc->view.x);
- src += pwc->vbandlength;
- pout_planar_y += bytes_per_block;
- pout_planar_u += pwc->view.x;
- pout_planar_v += pwc->view.x;
-
- }
+ int bandlines_left, bytes_per_block;
+ struct pwc_dec23_private *pdec = &pdev->dec23;
+
+ /* YUV420P image format */
+ unsigned char *pout_planar_y;
+ unsigned char *pout_planar_u;
+ unsigned char *pout_planar_v;
+ unsigned int plane_size;
+
+ mutex_lock(&pdec->lock);
+
+ bandlines_left = pdev->height / 4;
+ bytes_per_block = pdev->width * 4;
+ plane_size = pdev->height * pdev->width;
+
+ pout_planar_y = dst;
+ pout_planar_u = dst + plane_size;
+ pout_planar_v = dst + plane_size + plane_size / 4;
+
+ while (bandlines_left--) {
+ DecompressBand23(pdec, src,
+ pout_planar_y, pout_planar_u, pout_planar_v,
+ pdev->width, pdev->width);
+ src += pdev->vbandlength;
+ pout_planar_y += bytes_per_block;
+ pout_planar_u += pdev->width;
+ pout_planar_v += pdev->width;
}
+ mutex_unlock(&pdec->lock);
}
diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/video/pwc/pwc-dec23.h
index a0ac4f3dff81..c655b1c1e6a9 100644
--- a/drivers/media/video/pwc/pwc-dec23.h
+++ b/drivers/media/video/pwc/pwc-dec23.h
@@ -25,15 +25,20 @@
#ifndef PWC_DEC23_H
#define PWC_DEC23_H
-#include "pwc.h"
+struct pwc_device;
struct pwc_dec23_private
{
+ struct mutex lock;
+
+ unsigned char last_cmd, last_cmd_valid;
+
unsigned int scalebits;
unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */
unsigned int reservoir;
unsigned int nbits_in_reservoir;
+
const unsigned char *stream;
int temp_colors[16];
@@ -49,9 +54,8 @@ struct pwc_dec23_private
};
-int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd);
-void pwc_dec23_decompress(const struct pwc_device *pwc,
+void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd);
+void pwc_dec23_decompress(struct pwc_device *pdev,
const void *src,
- void *dst,
- int flags);
+ void *dst);
#endif
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 01ff643e682d..122fbd0081eb 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -128,33 +128,23 @@ static struct usb_driver pwc_driver = {
#define MAX_DEV_HINTS 20
#define MAX_ISOC_ERRORS 20
-static int default_fps = 10;
#ifdef CONFIG_USB_PWC_DEBUG
int pwc_trace = PWC_DEBUG_LEVEL;
#endif
static int power_save = -1;
-static int led_on = 100, led_off; /* defaults to LED that is on while in use */
-static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
-static struct {
- int type;
- char serial_number[30];
- int device_node;
- struct pwc_device *pdev;
-} device_hint[MAX_DEV_HINTS];
+static int leds[2] = { 100, 0 };
/***/
-static int pwc_video_open(struct file *file);
static int pwc_video_close(struct file *file);
static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
-static void pwc_video_release(struct video_device *vfd);
static const struct v4l2_file_operations pwc_fops = {
.owner = THIS_MODULE,
- .open = pwc_video_open,
+ .open = v4l2_fh_open,
.release = pwc_video_close,
.read = pwc_video_read,
.poll = pwc_video_poll,
@@ -163,7 +153,7 @@ static const struct v4l2_file_operations pwc_fops = {
};
static struct video_device pwc_template = {
.name = "Philips Webcam", /* Filled in later */
- .release = pwc_video_release,
+ .release = video_device_release_empty,
.fops = &pwc_fops,
.ioctl_ops = &pwc_ioctl_ops,
};
@@ -191,7 +181,6 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down)
{
if (down) {
PWC_TRACE("Snapshot button pressed.\n");
- pdev->snapshot_button_status = 1;
} else {
PWC_TRACE("Snapshot button released.\n");
}
@@ -375,6 +364,7 @@ static int pwc_isoc_init(struct pwc_device *pdev)
int i, j, ret;
struct usb_interface *intf;
struct usb_host_interface *idesc = NULL;
+ int compression = 0; /* 0..3 = uncompressed..high */
if (pdev->iso_init)
return 0;
@@ -386,6 +376,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
pdev->visoc_errors = 0;
udev = pdev->udev;
+retry:
+ /* We first try with low compression and then retry with a higher
+ compression setting if there is not enough bandwidth. */
+ ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt,
+ pdev->vframes, &compression, 1);
+
/* Get the current alternate interface, adjust packet size */
intf = usb_ifnum_to_if(udev, 0);
if (intf)
@@ -408,9 +404,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
}
/* Set alternate interface */
- ret = 0;
PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
+ if (ret == -ENOSPC && compression < 3) {
+ compression++;
+ goto retry;
+ }
if (ret < 0)
return ret;
@@ -454,6 +453,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
/* link */
for (i = 0; i < MAX_ISO_BUFS; i++) {
ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL);
+ if (ret == -ENOSPC && compression < 3) {
+ compression++;
+ pdev->iso_init = 1;
+ pwc_isoc_cleanup(pdev);
+ goto retry;
+ }
if (ret) {
PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
pdev->iso_init = 1;
@@ -517,12 +522,11 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
}
-/*
- * Release all queued buffers, no need to take queued_bufs_lock, since all
- * iso urbs have been killed when we're called so pwc_isoc_handler won't run.
- */
static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
while (!list_empty(&pdev->queued_bufs)) {
struct pwc_frame_buf *buf;
@@ -531,84 +535,7 @@ static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
list_del(&buf->list);
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
}
-}
-
-/*********
- * sysfs
- *********/
-static struct pwc_device *cd_to_pwc(struct device *cd)
-{
- struct video_device *vdev = to_video_device(cd);
- return video_get_drvdata(vdev);
-}
-
-static ssize_t show_pan_tilt(struct device *class_dev,
- struct device_attribute *attr, char *buf)
-{
- struct pwc_device *pdev = cd_to_pwc(class_dev);
- return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
-}
-
-static ssize_t store_pan_tilt(struct device *class_dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct pwc_device *pdev = cd_to_pwc(class_dev);
- int pan, tilt;
- int ret = -EINVAL;
-
- if (strncmp(buf, "reset", 5) == 0)
- ret = pwc_mpt_reset(pdev, 0x3);
-
- else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
- ret = pwc_mpt_set_angle(pdev, pan, tilt);
-
- if (ret < 0)
- return ret;
- return strlen(buf);
-}
-static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
- store_pan_tilt);
-
-static ssize_t show_snapshot_button_status(struct device *class_dev,
- struct device_attribute *attr, char *buf)
-{
- struct pwc_device *pdev = cd_to_pwc(class_dev);
- int status = pdev->snapshot_button_status;
- pdev->snapshot_button_status = 0;
- return sprintf(buf, "%d\n", status);
-}
-
-static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
- NULL);
-
-static int pwc_create_sysfs_files(struct pwc_device *pdev)
-{
- int rc;
-
- rc = device_create_file(&pdev->vdev.dev, &dev_attr_button);
- if (rc)
- goto err;
- if (pdev->features & FEATURE_MOTOR_PANTILT) {
- rc = device_create_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
- if (rc)
- goto err_button;
- }
-
- return 0;
-
-err_button:
- device_remove_file(&pdev->vdev.dev, &dev_attr_button);
-err:
- PWC_ERROR("Could not create sysfs files.\n");
- return rc;
-}
-
-static void pwc_remove_sysfs_files(struct pwc_device *pdev)
-{
- if (pdev->features & FEATURE_MOTOR_PANTILT)
- device_remove_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
- device_remove_file(&pdev->vdev.dev, &dev_attr_button);
+ spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
}
#ifdef CONFIG_USB_PWC_DEBUG
@@ -644,85 +571,60 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
/***************************************************************************/
/* Video4Linux functions */
-static int pwc_video_open(struct file *file)
+int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file)
{
- struct video_device *vdev = video_devdata(file);
- struct pwc_device *pdev;
-
- PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
-
- pdev = video_get_drvdata(vdev);
- if (!pdev->udev)
- return -ENODEV;
+ int r = 0;
- file->private_data = vdev;
- PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
- return 0;
+ mutex_lock(&pdev->capt_file_lock);
+ if (pdev->capt_file != NULL &&
+ pdev->capt_file != file) {
+ r = -EBUSY;
+ goto leave;
+ }
+ pdev->capt_file = file;
+leave:
+ mutex_unlock(&pdev->capt_file_lock);
+ return r;
}
-static void pwc_video_release(struct video_device *vfd)
+static void pwc_video_release(struct v4l2_device *v)
{
- struct pwc_device *pdev = container_of(vfd, struct pwc_device, vdev);
- int hint;
-
- /* search device_hint[] table if we occupy a slot, by any chance */
- for (hint = 0; hint < MAX_DEV_HINTS; hint++)
- if (device_hint[hint].pdev == pdev)
- device_hint[hint].pdev = NULL;
-
- /* Free intermediate decompression buffer & tables */
- if (pdev->decompress_data != NULL) {
- PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n",
- pdev->decompress_data);
- kfree(pdev->decompress_data);
- pdev->decompress_data = NULL;
- }
+ struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
v4l2_ctrl_handler_free(&pdev->ctrl_handler);
-
+ kfree(pdev->ctrl_buf);
kfree(pdev);
}
static int pwc_video_close(struct file *file)
{
- struct video_device *vdev = file->private_data;
- struct pwc_device *pdev;
-
- PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
+ struct pwc_device *pdev = video_drvdata(file);
- pdev = video_get_drvdata(vdev);
if (pdev->capt_file == file) {
vb2_queue_release(&pdev->vb_queue);
pdev->capt_file = NULL;
}
-
- PWC_DEBUG_OPEN("<< video_close()\n");
- return 0;
+ return v4l2_fh_release(file);
}
static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct video_device *vdev = file->private_data;
- struct pwc_device *pdev = video_get_drvdata(vdev);
+ struct pwc_device *pdev = video_drvdata(file);
if (!pdev->udev)
return -ENODEV;
- if (pdev->capt_file != NULL &&
- pdev->capt_file != file)
+ if (pwc_test_n_set_capt_file(pdev, file))
return -EBUSY;
- pdev->capt_file = file;
-
return vb2_read(&pdev->vb_queue, buf, count, ppos,
file->f_flags & O_NONBLOCK);
}
static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
{
- struct video_device *vdev = file->private_data;
- struct pwc_device *pdev = video_get_drvdata(vdev);
+ struct pwc_device *pdev = video_drvdata(file);
if (!pdev->udev)
return POLL_ERR;
@@ -732,8 +634,7 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct video_device *vdev = file->private_data;
- struct pwc_device *pdev = video_get_drvdata(vdev);
+ struct pwc_device *pdev = video_drvdata(file);
if (pdev->capt_file != file)
return -EBUSY;
@@ -749,6 +650,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned int sizes[], void *alloc_ctxs[])
{
struct pwc_device *pdev = vb2_get_drv_priv(vq);
+ int size;
if (*nbuffers < MIN_FRAMES)
*nbuffers = MIN_FRAMES;
@@ -757,7 +659,9 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
*nplanes = 1;
- sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
+ size = pwc_get_size(pdev, MAX_WIDTH, MAX_HEIGHT);
+ sizes[0] = PAGE_ALIGN(pwc_image_sizes[size][0] *
+ pwc_image_sizes[size][1] * 3 / 2);
return 0;
}
@@ -812,56 +716,59 @@ static void buffer_queue(struct vb2_buffer *vb)
unsigned long flags = 0;
spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
- list_add_tail(&buf->list, &pdev->queued_bufs);
+ /* Check the device has not disconnected between prep and queuing */
+ if (pdev->udev)
+ list_add_tail(&buf->list, &pdev->queued_bufs);
+ else
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
}
static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct pwc_device *pdev = vb2_get_drv_priv(vq);
+ int r;
- if (!pdev->udev)
- return -ENODEV;
+ mutex_lock(&pdev->udevlock);
+ if (!pdev->udev) {
+ r = -ENODEV;
+ goto leave;
+ }
/* Turn on camera and set LEDS on */
pwc_camera_power(pdev, 1);
- if (pdev->power_save) {
- /* Restore video mode */
- pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y,
- pdev->vframes, pdev->vcompression,
- pdev->vsnapshot);
- }
- pwc_set_leds(pdev, led_on, led_off);
+ pwc_set_leds(pdev, leds[0], leds[1]);
- return pwc_isoc_init(pdev);
+ r = pwc_isoc_init(pdev);
+ if (r) {
+ /* If we failed turn camera and LEDS back off */
+ pwc_set_leds(pdev, 0, 0);
+ pwc_camera_power(pdev, 0);
+ /* And cleanup any queued bufs!! */
+ pwc_cleanup_queued_bufs(pdev);
+ }
+leave:
+ mutex_unlock(&pdev->udevlock);
+ return r;
}
static int stop_streaming(struct vb2_queue *vq)
{
struct pwc_device *pdev = vb2_get_drv_priv(vq);
+ mutex_lock(&pdev->udevlock);
if (pdev->udev) {
pwc_set_leds(pdev, 0, 0);
pwc_camera_power(pdev, 0);
pwc_isoc_cleanup(pdev);
}
+ mutex_unlock(&pdev->udevlock);
+
pwc_cleanup_queued_bufs(pdev);
return 0;
}
-static void pwc_lock(struct vb2_queue *vq)
-{
- struct pwc_device *pdev = vb2_get_drv_priv(vq);
- mutex_lock(&pdev->modlock);
-}
-
-static void pwc_unlock(struct vb2_queue *vq)
-{
- struct pwc_device *pdev = vb2_get_drv_priv(vq);
- mutex_unlock(&pdev->modlock);
-}
-
static struct vb2_ops pwc_vb_queue_ops = {
.queue_setup = queue_setup,
.buf_init = buffer_init,
@@ -871,8 +778,6 @@ static struct vb2_ops pwc_vb_queue_ops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = pwc_unlock,
- .wait_finish = pwc_lock,
};
/***************************************************************************/
@@ -887,9 +792,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
struct usb_device *udev = interface_to_usbdev(intf);
struct pwc_device *pdev = NULL;
int vendor_id, product_id, type_id;
- int hint, rc;
+ int rc;
int features = 0;
- int video_nr = -1; /* default: use next available device */
+ int compression = 0;
int my_power_save = power_save;
char serial_number[30], *name;
@@ -1149,28 +1054,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
return -ENOMEM;
}
pdev->type = type_id;
- pdev->vframes = default_fps;
- strcpy(pdev->serial, serial_number);
pdev->features = features;
- if (vendor_id == 0x046D && product_id == 0x08B5) {
- /* Logitech QuickCam Orbit
- The ranges have been determined experimentally; they may differ from cam to cam.
- Also, the exact ranges left-right and up-down are different for my cam
- */
- pdev->angle_range.pan_min = -7000;
- pdev->angle_range.pan_max = 7000;
- pdev->angle_range.tilt_min = -3000;
- pdev->angle_range.tilt_max = 2500;
- }
pwc_construct(pdev); /* set min/max sizes correct */
- mutex_init(&pdev->modlock);
+ mutex_init(&pdev->capt_file_lock);
mutex_init(&pdev->udevlock);
spin_lock_init(&pdev->queued_bufs_lock);
INIT_LIST_HEAD(&pdev->queued_bufs);
pdev->udev = udev;
- pdev->vcompression = pwc_preferred_compression;
pdev->power_save = my_power_save;
/* Init videobuf2 queue structure */
@@ -1185,35 +1077,21 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
/* Init video_device structure */
memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
- pdev->vdev.parent = &intf->dev;
- pdev->vdev.lock = &pdev->modlock;
strcpy(pdev->vdev.name, name);
+ set_bit(V4L2_FL_USE_FH_PRIO, &pdev->vdev.flags);
video_set_drvdata(&pdev->vdev, pdev);
pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
- /* Now search device_hint[] table for a match, so we can hint a node number. */
- for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
- if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
- (device_hint[hint].pdev == NULL)) {
- /* so far, so good... try serial number */
- if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
- /* match! */
- video_nr = device_hint[hint].device_node;
- PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
- break;
- }
- }
+ /* Allocate USB command buffers */
+ pdev->ctrl_buf = kmalloc(sizeof(pdev->cmd_buf), GFP_KERNEL);
+ if (!pdev->ctrl_buf) {
+ PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
+ rc = -ENOMEM;
+ goto err_free_mem;
}
- /* occupy slot */
- if (hint < MAX_DEV_HINTS)
- device_hint[hint].pdev = pdev;
-
- PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
- usb_set_intfdata(intf, pdev);
-
#ifdef CONFIG_USB_PWC_DEBUG
/* Query sensor type */
if (pwc_get_cmos_sensor(pdev, &rc) >= 0) {
@@ -1227,8 +1105,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pwc_set_leds(pdev, 0, 0);
/* Setup intial videomode */
- rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y,
- pdev->vframes, pdev->vcompression, 0);
+ rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT,
+ V4L2_PIX_FMT_YUV420, 30, &compression, 1);
if (rc)
goto err_free_mem;
@@ -1239,20 +1117,25 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
goto err_free_mem;
}
- pdev->vdev.ctrl_handler = &pdev->ctrl_handler;
-
/* And powerdown the camera until streaming starts */
pwc_camera_power(pdev, 0);
- rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
- if (rc < 0) {
- PWC_ERROR("Failed to register as video device (%d).\n", rc);
+ /* Register the v4l2_device structure */
+ pdev->v4l2_dev.release = pwc_video_release;
+ rc = v4l2_device_register(&intf->dev, &pdev->v4l2_dev);
+ if (rc) {
+ PWC_ERROR("Failed to register v4l2-device (%d).\n", rc);
goto err_free_controls;
}
- rc = pwc_create_sysfs_files(pdev);
- if (rc)
- goto err_video_unreg;
+ pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler;
+ pdev->vdev.v4l2_dev = &pdev->v4l2_dev;
+
+ rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1);
+ if (rc < 0) {
+ PWC_ERROR("Failed to register as video device (%d).\n", rc);
+ goto err_unregister_v4l2_dev;
+ }
PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev));
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
@@ -1261,7 +1144,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
if (!pdev->button_dev) {
PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
rc = -ENOMEM;
- pwc_remove_sysfs_files(pdev);
goto err_video_unreg;
}
@@ -1279,7 +1161,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
if (rc) {
input_free_device(pdev->button_dev);
pdev->button_dev = NULL;
- pwc_remove_sysfs_files(pdev);
goto err_video_unreg;
}
#endif
@@ -1287,13 +1168,13 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
return 0;
err_video_unreg:
- if (hint < MAX_DEV_HINTS)
- device_hint[hint].pdev = NULL;
video_unregister_device(&pdev->vdev);
+err_unregister_v4l2_dev:
+ v4l2_device_unregister(&pdev->v4l2_dev);
err_free_controls:
v4l2_ctrl_handler_free(&pdev->ctrl_handler);
err_free_mem:
- usb_set_intfdata(intf, NULL);
+ kfree(pdev->ctrl_buf);
kfree(pdev);
return rc;
}
@@ -1301,27 +1182,26 @@ err_free_mem:
/* The user yanked out the cable... */
static void usb_pwc_disconnect(struct usb_interface *intf)
{
- struct pwc_device *pdev = usb_get_intfdata(intf);
+ struct v4l2_device *v = usb_get_intfdata(intf);
+ struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
mutex_lock(&pdev->udevlock);
- mutex_lock(&pdev->modlock);
-
- usb_set_intfdata(intf, NULL);
/* No need to keep the urbs around after disconnection */
pwc_isoc_cleanup(pdev);
- pwc_cleanup_queued_bufs(pdev);
pdev->udev = NULL;
-
- mutex_unlock(&pdev->modlock);
mutex_unlock(&pdev->udevlock);
- pwc_remove_sysfs_files(pdev);
+ pwc_cleanup_queued_bufs(pdev);
+
video_unregister_device(&pdev->vdev);
+ v4l2_device_unregister(&pdev->v4l2_dev);
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
if (pdev->button_dev)
input_unregister_device(pdev->button_dev);
#endif
+
+ v4l2_device_put(&pdev->v4l2_dev);
}
@@ -1329,30 +1209,19 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
* Initialization code & module stuff
*/
-static int fps;
-static int compression = -1;
-static int leds[2] = { -1, -1 };
static unsigned int leds_nargs;
-static char *dev_hint[MAX_DEV_HINTS];
-static unsigned int dev_hint_nargs;
-module_param(fps, int, 0444);
#ifdef CONFIG_USB_PWC_DEBUG
module_param_named(trace, pwc_trace, int, 0644);
#endif
module_param(power_save, int, 0644);
-module_param(compression, int, 0444);
module_param_array(leds, int, &leds_nargs, 0444);
-module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
-MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
#ifdef CONFIG_USB_PWC_DEBUG
MODULE_PARM_DESC(trace, "For debugging purposes");
#endif
MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off");
-MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
-MODULE_PARM_DESC(dev_hint, "Device node hints");
MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
@@ -1362,122 +1231,13 @@ MODULE_VERSION( PWC_VERSION );
static int __init usb_pwc_init(void)
{
- int i;
-
-#ifdef CONFIG_USB_PWC_DEBUG
- PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
- PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
- PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
- PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
-
- if (pwc_trace >= 0) {
- PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
- }
-#endif
-
- if (fps) {
- if (fps < 4 || fps > 30) {
- PWC_ERROR("Framerate out of bounds (4-30).\n");
- return -EINVAL;
- }
- default_fps = fps;
- PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
- }
-
- if (compression >= 0) {
- if (compression > 3) {
- PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
- return -EINVAL;
- }
- pwc_preferred_compression = compression;
- PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
- }
- if (leds[0] >= 0)
- led_on = leds[0];
- if (leds[1] >= 0)
- led_off = leds[1];
-
- /* Big device node whoopla. Basically, it allows you to assign a
- device node (/dev/videoX) to a camera, based on its type
- & serial number. The format is [type[.serialnumber]:]node.
-
- Any camera that isn't matched by these rules gets the next
- available free device node.
- */
- for (i = 0; i < MAX_DEV_HINTS; i++) {
- char *s, *colon, *dot;
-
- /* This loop also initializes the array */
- device_hint[i].pdev = NULL;
- s = dev_hint[i];
- if (s != NULL && *s != '\0') {
- device_hint[i].type = -1; /* wildcard */
- strcpy(device_hint[i].serial_number, "*");
-
- /* parse string: chop at ':' & '/' */
- colon = dot = s;
- while (*colon != '\0' && *colon != ':')
- colon++;
- while (*dot != '\0' && *dot != '.')
- dot++;
- /* Few sanity checks */
- if (*dot != '\0' && dot > colon) {
- PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
- return -EINVAL;
- }
-
- if (*colon == '\0') {
- /* No colon */
- if (*dot != '\0') {
- PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
- return -EINVAL;
- }
- else {
- /* No type or serial number specified, just a number. */
- device_hint[i].device_node =
- simple_strtol(s, NULL, 10);
- }
- }
- else {
- /* There's a colon, so we have at least a type and a device node */
- device_hint[i].type =
- simple_strtol(s, NULL, 10);
- device_hint[i].device_node =
- simple_strtol(colon + 1, NULL, 10);
- if (*dot != '\0') {
- /* There's a serial number as well */
- int k;
-
- dot++;
- k = 0;
- while (*dot != ':' && k < 29) {
- device_hint[i].serial_number[k++] = *dot;
- dot++;
- }
- device_hint[i].serial_number[k] = '\0';
- }
- }
- PWC_TRACE("device_hint[%d]:\n", i);
- PWC_TRACE(" type : %d\n", device_hint[i].type);
- PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number);
- PWC_TRACE(" node : %d\n", device_hint[i].device_node);
- }
- else
- device_hint[i].type = 0; /* not filled */
- } /* ..for MAX_DEV_HINTS */
-
- PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
return usb_register(&pwc_driver);
}
static void __exit usb_pwc_exit(void)
{
- PWC_DEBUG_MODULE("Deregistering driver.\n");
usb_deregister(&pwc_driver);
- PWC_INFO("Philips webcam module removed.\n");
}
module_init(usb_pwc_init);
module_exit(usb_pwc_exit);
-
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h
index 047dad8c15f7..8e02b7ac2139 100644
--- a/drivers/media/video/pwc/pwc-kiara.h
+++ b/drivers/media/video/pwc/pwc-kiara.h
@@ -27,7 +27,7 @@
#ifndef PWC_KIARA_H
#define PWC_KIARA_H
-#include <media/pwc-ioctl.h>
+#include "pwc.h"
#define PWC_FPS_MAX_KIARA 6
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c
index 0b031336eab8..9be5adffa874 100644
--- a/drivers/media/video/pwc/pwc-misc.c
+++ b/drivers/media/video/pwc/pwc-misc.c
@@ -27,67 +27,47 @@
#include "pwc.h"
-const struct pwc_coord pwc_image_sizes[PSZ_MAX] =
+const int pwc_image_sizes[PSZ_MAX][2] =
{
- { 128, 96, 0 }, /* sqcif */
- { 160, 120, 0 }, /* qsif */
- { 176, 144, 0 }, /* qcif */
- { 320, 240, 0 }, /* sif */
- { 352, 288, 0 }, /* cif */
- { 640, 480, 0 }, /* vga */
+ { 128, 96 }, /* sqcif */
+ { 160, 120 }, /* qsif */
+ { 176, 144 }, /* qcif */
+ { 320, 240 }, /* sif */
+ { 352, 288 }, /* cif */
+ { 640, 480 }, /* vga */
};
/* x,y -> PSZ_ */
-int pwc_decode_size(struct pwc_device *pdev, int width, int height)
+int pwc_get_size(struct pwc_device *pdev, int width, int height)
{
- int i, find;
-
- /* Make sure we don't go beyond our max size.
- NB: we have different limits for RAW and normal modes. In case
- you don't have the decompressor loaded or use RAW mode,
- the maximum viewable size is smaller.
- */
- if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
- {
- if (width > pdev->abs_max.x || height > pdev->abs_max.y)
- {
- PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
- return -1;
- }
- }
- else
- {
- if (width > pdev->view_max.x || height > pdev->view_max.y)
- {
- PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
- return -1;
- }
- }
+ int i;
/* Find the largest size supported by the camera that fits into the
- requested size.
- */
- find = -1;
+ requested size. */
+ for (i = PSZ_MAX - 1; i >= 0; i--) {
+ if (!(pdev->image_mask & (1 << i)))
+ continue;
+
+ if (pwc_image_sizes[i][0] <= width &&
+ pwc_image_sizes[i][1] <= height)
+ return i;
+ }
+
+ /* No mode found, return the smallest mode we have */
for (i = 0; i < PSZ_MAX; i++) {
- if (pdev->image_mask & (1 << i)) {
- if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height)
- find = i;
- }
+ if (pdev->image_mask & (1 << i))
+ return i;
}
- return find;
+
+ /* Never reached there always is atleast one supported mode */
+ return 0;
}
-/* initialize variables depending on type and decompressor*/
+/* initialize variables depending on type and decompressor */
void pwc_construct(struct pwc_device *pdev)
{
if (DEVICE_USE_CODEC1(pdev->type)) {
- pdev->view_min.x = 128;
- pdev->view_min.y = 96;
- pdev->view_max.x = 352;
- pdev->view_max.y = 288;
- pdev->abs_max.x = 352;
- pdev->abs_max.y = 288;
pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF;
pdev->vcinterface = 2;
pdev->vendpoint = 4;
@@ -96,13 +76,7 @@ void pwc_construct(struct pwc_device *pdev)
} else if (DEVICE_USE_CODEC3(pdev->type)) {
- pdev->view_min.x = 160;
- pdev->view_min.y = 120;
- pdev->view_max.x = 640;
- pdev->view_max.y = 480;
pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
- pdev->abs_max.x = 640;
- pdev->abs_max.y = 480;
pdev->vcinterface = 3;
pdev->vendpoint = 5;
pdev->frame_header_size = TOUCAM_HEADER_SIZE;
@@ -110,20 +84,10 @@ void pwc_construct(struct pwc_device *pdev)
} else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
- pdev->view_min.x = 128;
- pdev->view_min.y = 96;
- /* Anthill bug #38: PWC always reports max size, even without PWCX */
- pdev->view_max.x = 640;
- pdev->view_max.y = 480;
pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
- pdev->abs_max.x = 640;
- pdev->abs_max.y = 480;
pdev->vcinterface = 3;
pdev->vendpoint = 4;
pdev->frame_header_size = 0;
pdev->frame_trailer_size = 0;
}
- pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */
- pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
- pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
}
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h
index a6e22224c95f..270c5b9010f6 100644
--- a/drivers/media/video/pwc/pwc-timon.h
+++ b/drivers/media/video/pwc/pwc-timon.h
@@ -42,7 +42,7 @@
#ifndef PWC_TIMON_H
#define PWC_TIMON_H
-#include <media/pwc-ioctl.h>
+#include "pwc.h"
#define PWC_FPS_MAX_TIMON 6
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c
index 51265092bd31..b65903fbcf0d 100644
--- a/drivers/media/video/pwc/pwc-uncompress.c
+++ b/drivers/media/video/pwc/pwc-uncompress.c
@@ -35,7 +35,7 @@
int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
{
- int n, line, col, stride;
+ int n, line, col;
void *yuv, *image;
u16 *src;
u16 *dsty, *dstu, *dstv;
@@ -60,35 +60,23 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
return 0;
}
- vb2_set_plane_payload(&fbuf->vb, 0, pdev->view.size);
+ vb2_set_plane_payload(&fbuf->vb, 0,
+ pdev->width * pdev->height * 3 / 2);
if (pdev->vbandlength == 0) {
/* Uncompressed mode.
- * We copy the data into the output buffer, using the viewport
- * size (which may be larger than the image size).
- * Unfortunately we have to do a bit of byte stuffing to get
- * the desired output format/size.
*
* We do some byte shuffling here to go from the
* native format to YUV420P.
*/
src = (u16 *)yuv;
- n = pdev->view.x * pdev->view.y;
+ n = pdev->width * pdev->height;
+ dsty = (u16 *)(image);
+ dstu = (u16 *)(image + n);
+ dstv = (u16 *)(image + n + n / 4);
- /* offset in Y plane */
- stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
- dsty = (u16 *)(image + stride);
-
- /* offsets in U/V planes */
- stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
- dstu = (u16 *)(image + n + stride);
- dstv = (u16 *)(image + n + n / 4 + stride);
-
- /* increment after each line */
- stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
-
- for (line = 0; line < pdev->image.y; line++) {
- for (col = 0; col < pdev->image.x; col += 4) {
+ for (line = 0; line < pdev->height; line++) {
+ for (col = 0; col < pdev->width; col += 4) {
*dsty++ = *src++;
*dsty++ = *src++;
if (line & 1)
@@ -96,11 +84,6 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
else
*dstu++ = *src++;
}
- dsty += stride;
- if (line & 1)
- dstv += (stride >> 1);
- else
- dstu += (stride >> 1);
}
return 0;
@@ -111,12 +94,6 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
* the decompressor routines will write the data in planar format
* immediately.
*/
- if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) {
- PWC_ERROR("Mode Bayer is not supported for now\n");
- /* flags |= PWCX_FLAG_BAYER; */
- return -ENXIO; /* No such device or address: missing decompressor */
- }
-
if (DEVICE_USE_CODEC1(pdev->type)) {
/* TODO & FIXME */
@@ -124,10 +101,7 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
return -ENXIO; /* No such device or address: missing decompressor */
} else {
- pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR);
+ pwc_dec23_decompress(pdev, yuv, image);
}
return 0;
}
-
-
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index a10ff6b64acf..2834e3e65b39 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -49,6 +49,7 @@ static const struct v4l2_ctrl_ops pwc_ctrl_ops = {
enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto };
enum { custom_autocontour, custom_contour, custom_noise_reduction,
+ custom_awb_speed, custom_awb_delay,
custom_save_user, custom_restore_user, custom_restore_factory };
const char * const pwc_auto_whitebal_qmenu[] = {
@@ -138,6 +139,26 @@ static const struct v4l2_ctrl_config pwc_restore_factory_cfg = {
.name = "Restore Factory Settings",
};
+static const struct v4l2_ctrl_config pwc_awb_speed_cfg = {
+ .ops = &pwc_ctrl_ops,
+ .id = PWC_CID_CUSTOM(awb_speed),
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Auto White Balance Speed",
+ .min = 1,
+ .max = 32,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_awb_delay_cfg = {
+ .ops = &pwc_ctrl_ops,
+ .id = PWC_CID_CUSTOM(awb_delay),
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Auto White Balance Delay",
+ .min = 0,
+ .max = 63,
+ .step = 1,
+};
+
int pwc_init_controls(struct pwc_device *pdev)
{
struct v4l2_ctrl_handler *hdl;
@@ -338,6 +359,23 @@ int pwc_init_controls(struct pwc_device *pdev)
if (pdev->restore_factory)
pdev->restore_factory->flags |= V4L2_CTRL_FLAG_UPDATE;
+ /* Auto White Balance speed & delay */
+ r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL,
+ AWB_CONTROL_SPEED_FORMATTER, &def);
+ if (r || def < 1 || def > 32)
+ def = 1;
+ cfg = pwc_awb_speed_cfg;
+ cfg.def = def;
+ pdev->awb_speed = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
+ r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL,
+ AWB_CONTROL_DELAY_FORMATTER, &def);
+ if (r || def > 63)
+ def = 0;
+ cfg = pwc_awb_delay_cfg;
+ cfg.def = def;
+ pdev->awb_delay = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
if (!(pdev->features & FEATURE_MOTOR_PANTILT))
return hdl->error;
@@ -357,25 +395,16 @@ int pwc_init_controls(struct pwc_device *pdev)
return hdl->error;
}
-static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
+static void pwc_vidioc_fill_fmt(struct v4l2_format *f,
+ int width, int height, u32 pixfmt)
{
memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
- f->fmt.pix.width = pdev->view.x;
- f->fmt.pix.height = pdev->view.y;
+ f->fmt.pix.width = width;
+ f->fmt.pix.height = height;
f->fmt.pix.field = V4L2_FIELD_NONE;
- if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
- f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
- } else {
- /* vbandlength contains 4 lines ... */
- f->fmt.pix.bytesperline = pdev->vbandlength/4;
- f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
- if (DEVICE_USE_CODEC1(pdev->type))
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1;
- else
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2;
- }
+ f->fmt.pix.pixelformat = pixfmt;
+ f->fmt.pix.bytesperline = f->fmt.pix.width;
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.width * 3 / 2;
PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
"width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
f->fmt.pix.width,
@@ -391,6 +420,8 @@ static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_forma
/* ioctl(VIDIOC_TRY_FMT) */
static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
{
+ int size;
+
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
return -EINVAL;
@@ -417,15 +448,11 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
}
- if (f->fmt.pix.width > pdev->view_max.x)
- f->fmt.pix.width = pdev->view_max.x;
- else if (f->fmt.pix.width < pdev->view_min.x)
- f->fmt.pix.width = pdev->view_min.x;
-
- if (f->fmt.pix.height > pdev->view_max.y)
- f->fmt.pix.height = pdev->view_max.y;
- else if (f->fmt.pix.height < pdev->view_min.y)
- f->fmt.pix.height = pdev->view_min.y;
+ size = pwc_get_size(pdev, f->fmt.pix.width, f->fmt.pix.height);
+ pwc_vidioc_fill_fmt(f,
+ pwc_image_sizes[size][0],
+ pwc_image_sizes[size][1],
+ f->fmt.pix.pixelformat);
return 0;
}
@@ -435,68 +462,45 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
struct pwc_device *pdev = video_drvdata(file);
- int ret, fps, snapshot, compression, pixelformat;
-
- if (!pdev->udev)
- return -ENODEV;
+ int ret, pixelformat, compression = 0;
- if (pdev->capt_file != NULL &&
- pdev->capt_file != file)
+ if (pwc_test_n_set_capt_file(pdev, file))
return -EBUSY;
- pdev->capt_file = file;
-
ret = pwc_vidioc_try_fmt(pdev, f);
- if (ret<0)
+ if (ret < 0)
return ret;
pixelformat = f->fmt.pix.pixelformat;
- compression = pdev->vcompression;
- snapshot = 0;
- fps = pdev->vframes;
- if (f->fmt.pix.priv) {
- compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
- snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
- fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
- if (fps == 0)
- fps = pdev->vframes;
- }
- if (pixelformat != V4L2_PIX_FMT_YUV420 &&
- pixelformat != V4L2_PIX_FMT_PWC1 &&
- pixelformat != V4L2_PIX_FMT_PWC2)
- return -EINVAL;
+ mutex_lock(&pdev->udevlock);
+ if (!pdev->udev) {
+ ret = -ENODEV;
+ goto leave;
+ }
- if (vb2_is_streaming(&pdev->vb_queue))
- return -EBUSY;
+ if (pdev->iso_init) {
+ ret = -EBUSY;
+ goto leave;
+ }
PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
- "compression=%d snapshot=%d format=%c%c%c%c\n",
- f->fmt.pix.width, f->fmt.pix.height, fps,
- compression, snapshot,
+ "format=%c%c%c%c\n",
+ f->fmt.pix.width, f->fmt.pix.height, pdev->vframes,
(pixelformat)&255,
(pixelformat>>8)&255,
(pixelformat>>16)&255,
(pixelformat>>24)&255);
- ret = pwc_set_video_mode(pdev,
- f->fmt.pix.width,
- f->fmt.pix.height,
- fps,
- compression,
- snapshot);
+ ret = pwc_set_video_mode(pdev, f->fmt.pix.width, f->fmt.pix.height,
+ pixelformat, 30, &compression, 0);
PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret);
- if (ret)
- return ret;
-
- pdev->pixfmt = pixelformat;
-
- pwc_vidioc_fill_fmt(pdev, f);
-
- return 0;
-
+ pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt);
+leave:
+ mutex_unlock(&pdev->udevlock);
+ return ret;
}
static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
@@ -536,30 +540,14 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i)
return i ? -EINVAL : 0;
}
-static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+static int pwc_g_volatile_ctrl_unlocked(struct v4l2_ctrl *ctrl)
{
struct pwc_device *pdev =
container_of(ctrl->handler, struct pwc_device, ctrl_handler);
int ret = 0;
- /*
- * Sometimes it can take quite long for the pwc to complete usb control
- * transfers, so release the modlock to give streaming by another
- * process / thread the chance to continue with a dqbuf.
- */
- mutex_unlock(&pdev->modlock);
-
- /*
- * Take the udev-lock to protect against the disconnect handler
- * completing and setting dev->udev to NULL underneath us. Other code
- * does not need to do this since it is protected by the modlock.
- */
- mutex_lock(&pdev->udevlock);
-
- if (!pdev->udev) {
- ret = -ENODEV;
- goto leave;
- }
+ if (!pdev->udev)
+ return -ENODEV;
switch (ctrl->id) {
case V4L2_CID_AUTO_WHITE_BALANCE:
@@ -624,9 +612,18 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
if (ret)
PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret);
-leave:
+ return ret;
+}
+
+static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct pwc_device *pdev =
+ container_of(ctrl->handler, struct pwc_device, ctrl_handler);
+ int ret;
+
+ mutex_lock(&pdev->udevlock);
+ ret = pwc_g_volatile_ctrl_unlocked(ctrl);
mutex_unlock(&pdev->udevlock);
- mutex_lock(&pdev->modlock);
return ret;
}
@@ -643,6 +640,15 @@ static int pwc_set_awb(struct pwc_device *pdev)
if (pdev->auto_white_balance->val != awb_manual)
pdev->color_bal_valid = false; /* Force cache update */
+
+ /*
+ * If this is a preset, update our red / blue balance values
+ * so that events get generated for the new preset values
+ */
+ if (pdev->auto_white_balance->val == awb_indoor ||
+ pdev->auto_white_balance->val == awb_outdoor ||
+ pdev->auto_white_balance->val == awb_fl)
+ pwc_g_volatile_ctrl_unlocked(pdev->auto_white_balance);
}
if (pdev->auto_white_balance->val != awb_manual)
return 0;
@@ -766,33 +772,33 @@ static int pwc_set_autogain_expo(struct pwc_device *pdev)
static int pwc_set_motor(struct pwc_device *pdev)
{
int ret;
- u8 buf[4];
- buf[0] = 0;
+ pdev->ctrl_buf[0] = 0;
if (pdev->motor_pan_reset->is_new)
- buf[0] |= 0x01;
+ pdev->ctrl_buf[0] |= 0x01;
if (pdev->motor_tilt_reset->is_new)
- buf[0] |= 0x02;
+ pdev->ctrl_buf[0] |= 0x02;
if (pdev->motor_pan_reset->is_new || pdev->motor_tilt_reset->is_new) {
ret = send_control_msg(pdev, SET_MPT_CTL,
- PT_RESET_CONTROL_FORMATTER, buf, 1);
+ PT_RESET_CONTROL_FORMATTER,
+ pdev->ctrl_buf, 1);
if (ret < 0)
return ret;
}
- memset(buf, 0, sizeof(buf));
+ memset(pdev->ctrl_buf, 0, 4);
if (pdev->motor_pan->is_new) {
- buf[0] = pdev->motor_pan->val & 0xFF;
- buf[1] = (pdev->motor_pan->val >> 8);
+ pdev->ctrl_buf[0] = pdev->motor_pan->val & 0xFF;
+ pdev->ctrl_buf[1] = (pdev->motor_pan->val >> 8);
}
if (pdev->motor_tilt->is_new) {
- buf[2] = pdev->motor_tilt->val & 0xFF;
- buf[3] = (pdev->motor_tilt->val >> 8);
+ pdev->ctrl_buf[2] = pdev->motor_tilt->val & 0xFF;
+ pdev->ctrl_buf[3] = (pdev->motor_tilt->val >> 8);
}
if (pdev->motor_pan->is_new || pdev->motor_tilt->is_new) {
ret = send_control_msg(pdev, SET_MPT_CTL,
PT_RELATIVE_CONTROL_FORMATTER,
- buf, sizeof(buf));
+ pdev->ctrl_buf, 4);
if (ret < 0)
return ret;
}
@@ -806,8 +812,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
container_of(ctrl->handler, struct pwc_device, ctrl_handler);
int ret = 0;
- /* See the comments on locking in pwc_g_volatile_ctrl */
- mutex_unlock(&pdev->modlock);
mutex_lock(&pdev->udevlock);
if (!pdev->udev) {
@@ -891,6 +895,16 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
ret = pwc_button_ctrl(pdev,
RESTORE_FACTORY_DEFAULTS_FORMATTER);
break;
+ case PWC_CID_CUSTOM(awb_speed):
+ ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+ AWB_CONTROL_SPEED_FORMATTER,
+ ctrl->val);
+ break;
+ case PWC_CID_CUSTOM(awb_delay):
+ ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+ AWB_CONTROL_DELAY_FORMATTER,
+ ctrl->val);
+ break;
case V4L2_CID_PAN_RELATIVE:
ret = pwc_set_motor(pdev);
break;
@@ -903,7 +917,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
leave:
mutex_unlock(&pdev->udevlock);
- mutex_lock(&pdev->modlock);
return ret;
}
@@ -933,9 +946,14 @@ static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
struct pwc_device *pdev = video_drvdata(file);
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&pdev->udevlock); /* To avoid race with s_fmt */
PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
- pdev->image.x, pdev->image.y);
- pwc_vidioc_fill_fmt(pdev, f);
+ pdev->width, pdev->height);
+ pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt);
+ mutex_unlock(&pdev->udevlock);
return 0;
}
@@ -951,12 +969,9 @@ static int pwc_reqbufs(struct file *file, void *fh,
{
struct pwc_device *pdev = video_drvdata(file);
- if (pdev->capt_file != NULL &&
- pdev->capt_file != file)
+ if (pwc_test_n_set_capt_file(pdev, file))
return -EBUSY;
- pdev->capt_file = file;
-
return vb2_reqbufs(&pdev->vb_queue, rb);
}
@@ -1025,25 +1040,21 @@ static int pwc_enum_framesizes(struct file *file, void *fh,
struct pwc_device *pdev = video_drvdata(file);
unsigned int i = 0, index = fsize->index;
- if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
+ if (fsize->pixel_format == V4L2_PIX_FMT_YUV420 ||
+ (fsize->pixel_format == V4L2_PIX_FMT_PWC1 &&
+ DEVICE_USE_CODEC1(pdev->type)) ||
+ (fsize->pixel_format == V4L2_PIX_FMT_PWC2 &&
+ DEVICE_USE_CODEC23(pdev->type))) {
for (i = 0; i < PSZ_MAX; i++) {
- if (pdev->image_mask & (1UL << i)) {
- if (!index--) {
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = pwc_image_sizes[i].x;
- fsize->discrete.height = pwc_image_sizes[i].y;
- return 0;
- }
+ if (!(pdev->image_mask & (1UL << i)))
+ continue;
+ if (!index--) {
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = pwc_image_sizes[i][0];
+ fsize->discrete.height = pwc_image_sizes[i][1];
+ return 0;
}
}
- } else if (fsize->index == 0 &&
- ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
- (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
-
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = pdev->abs_max.x;
- fsize->discrete.height = pdev->abs_max.y;
- return 0;
}
return -EINVAL;
}
@@ -1056,8 +1067,8 @@ static int pwc_enum_frameintervals(struct file *file, void *fh,
unsigned int i;
for (i = 0; i < PSZ_MAX; i++) {
- if (pwc_image_sizes[i].x == fival->width &&
- pwc_image_sizes[i].y == fival->height) {
+ if (pwc_image_sizes[i][0] == fival->width &&
+ pwc_image_sizes[i][1] == fival->height) {
size = i;
break;
}
@@ -1078,20 +1089,61 @@ static int pwc_enum_frameintervals(struct file *file, void *fh,
return 0;
}
-static int pwc_log_status(struct file *file, void *priv)
+static int pwc_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
{
struct pwc_device *pdev = video_drvdata(file);
- v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME);
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(parm, 0, sizeof(*parm));
+
+ parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ parm->parm.capture.readbuffers = MIN_FRAMES;
+ parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.timeperframe.denominator = pdev->vframes;
+ parm->parm.capture.timeperframe.numerator = 1;
+
return 0;
}
-static long pwc_default(struct file *file, void *fh, bool valid_prio,
- int cmd, void *arg)
+static int pwc_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
{
struct pwc_device *pdev = video_drvdata(file);
+ int compression = 0;
+ int ret, fps;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ parm->parm.capture.timeperframe.numerator == 0)
+ return -EINVAL;
+
+ if (pwc_test_n_set_capt_file(pdev, file))
+ return -EBUSY;
+
+ fps = parm->parm.capture.timeperframe.denominator /
+ parm->parm.capture.timeperframe.numerator;
- return pwc_ioctl(pdev, cmd, arg);
+ mutex_lock(&pdev->udevlock);
+ if (!pdev->udev) {
+ ret = -ENODEV;
+ goto leave;
+ }
+
+ if (pdev->iso_init) {
+ ret = -EBUSY;
+ goto leave;
+ }
+
+ ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt,
+ fps, &compression, 0);
+
+ pwc_g_parm(file, fh, parm);
+
+leave:
+ mutex_unlock(&pdev->udevlock);
+ return ret;
}
const struct v4l2_ioctl_ops pwc_ioctl_ops = {
@@ -1109,11 +1161,9 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = {
.vidioc_dqbuf = pwc_dqbuf,
.vidioc_streamon = pwc_streamon,
.vidioc_streamoff = pwc_streamoff,
- .vidioc_log_status = pwc_log_status,
+ .vidioc_log_status = v4l2_ctrl_log_status,
.vidioc_enum_framesizes = pwc_enum_framesizes,
.vidioc_enum_frameintervals = pwc_enum_frameintervals,
- .vidioc_default = pwc_default,
+ .vidioc_g_parm = pwc_g_parm,
+ .vidioc_s_parm = pwc_s_parm,
};
-
-
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 0e4e2d7b7872..e4d4d711dd1f 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -35,14 +35,17 @@
#include <asm/errno.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
#include <media/videobuf2-vmalloc.h>
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
#include <linux/input.h>
#endif
-
-#include <media/pwc-ioctl.h>
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
/* Version block */
#define PWC_VERSION "10.0.15"
@@ -106,6 +109,9 @@
#define FEATURE_CODEC1 0x0002
#define FEATURE_CODEC2 0x0004
+#define MAX_WIDTH 640
+#define MAX_HEIGHT 480
+
/* Ignore errors in the first N frames, to allow for startup delays */
#define FRAME_LOWMARK 5
@@ -128,9 +134,6 @@
#define DEVICE_USE_CODEC3(x) ((x)>=700)
#define DEVICE_USE_CODEC23(x) ((x)>=675)
-/* from pwc-dec.h */
-#define PWCX_FLAG_PLANAR 0x0001
-
/* Request types: video */
#define SET_LUM_CTL 0x01
#define GET_LUM_CTL 0x02
@@ -186,6 +189,24 @@
#define PT_RESET_CONTROL_FORMATTER 0x02
#define PT_STATUS_FORMATTER 0x03
+/* Enumeration of image sizes */
+#define PSZ_SQCIF 0x00
+#define PSZ_QSIF 0x01
+#define PSZ_QCIF 0x02
+#define PSZ_SIF 0x03
+#define PSZ_CIF 0x04
+#define PSZ_VGA 0x05
+#define PSZ_MAX 6
+
+struct pwc_raw_frame {
+ __le16 type; /* type of the webcam */
+ __le16 vbandlength; /* Size of 4 lines compressed (used by the
+ decompressor) */
+ __u8 cmd[4]; /* the four byte of the command (in case of
+ nala, only the first 3 bytes is filled) */
+ __u8 rawframe[0]; /* frame_size = H / 4 * vbandlength */
+} __packed;
+
/* intermediate buffers with raw data from the USB cam */
struct pwc_frame_buf
{
@@ -198,39 +219,36 @@ struct pwc_frame_buf
struct pwc_device
{
struct video_device vdev;
- struct mutex modlock;
+ struct v4l2_device v4l2_dev;
/* Pointer to our usb_device, may be NULL after unplug */
struct usb_device *udev;
- /* Protects the setting of udev to NULL by our disconnect handler */
struct mutex udevlock;
/* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
int type;
int release; /* release number */
int features; /* feature bits */
- char serial[30]; /* serial number (string) */
/*** Video data ***/
struct file *capt_file; /* file doing video capture */
+ struct mutex capt_file_lock;
int vendpoint; /* video isoc endpoint */
int vcinterface; /* video control interface */
int valternate; /* alternate interface needed */
- int vframes, vsize; /* frames-per-second & size (see PSZ_*) */
+ int vframes; /* frames-per-second */
int pixfmt; /* pixelformat: V4L2_PIX_FMT_YUV420 or _PWCX */
int vframe_count; /* received frames */
int vmax_packet_size; /* USB maxpacket size */
int vlast_packet_size; /* for frame synchronisation */
int visoc_errors; /* number of contiguous ISOC errors */
- int vcompression; /* desired compression factor */
int vbandlength; /* compressed band length; 0 is uncompressed */
- char vsnapshot; /* snapshot mode */
char vsync; /* used by isoc handler */
char vmirror; /* for ToUCaM series */
char power_save; /* Do powersaving for this cam */
- int cmd_len;
unsigned char cmd_buf[13];
+ unsigned char *ctrl_buf;
struct urb *urbs[MAX_ISO_BUFS];
char iso_init;
@@ -253,7 +271,10 @@ struct pwc_device
int frame_total_size; /* including header & trailer */
int drop_frames;
- void *decompress_data; /* private data for decompression engine */
+ union { /* private data for decompression engine */
+ struct pwc_dec1_private dec1;
+ struct pwc_dec23_private dec23;
+ };
/*
* We have an 'image' and a 'view', where 'image' is the fixed-size img
@@ -262,21 +283,8 @@ struct pwc_device
* a gray or black border. view_min <= image <= view <= view_max;
*/
int image_mask; /* supported sizes */
- struct pwc_coord view_min, view_max; /* minimum and maximum view */
- struct pwc_coord abs_max; /* maximum supported size */
- struct pwc_coord image, view; /* image and viewport size */
- struct pwc_coord offset; /* offset of the viewport */
+ int width, height; /* current resolution */
- /*** motorized pan/tilt feature */
- struct pwc_mpt_range angle_range;
- int pan_angle; /* in degrees * 100 */
- int tilt_angle; /* absolute angle; 0,0 is home */
-
- /*
- * Set to 1 when the user push the button, reset to 0
- * when this value is read from sysfs.
- */
- int snapshot_button_status;
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
struct input_dev *button_dev; /* webcam snapshot button input */
char button_phys[64];
@@ -328,6 +336,8 @@ struct pwc_device
struct v4l2_ctrl *save_user;
struct v4l2_ctrl *restore_user;
struct v4l2_ctrl *restore_factory;
+ struct v4l2_ctrl *awb_speed;
+ struct v4l2_ctrl *awb_delay;
struct {
/* motor control cluster */
struct v4l2_ctrl *motor_pan;
@@ -344,19 +354,20 @@ struct pwc_device
extern int pwc_trace;
#endif
+int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file);
+
/** Functions in pwc-misc.c */
/* sizes in pixels */
-extern const struct pwc_coord pwc_image_sizes[PSZ_MAX];
+extern const int pwc_image_sizes[PSZ_MAX][2];
-int pwc_decode_size(struct pwc_device *pdev, int width, int height);
+int pwc_get_size(struct pwc_device *pdev, int width, int height);
void pwc_construct(struct pwc_device *pdev);
/** Functions in pwc-ctrl.c */
/* Request a certain video mode. Returns < 0 if not possible */
-extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
+ int pixfmt, int frames, int *compression, int send_to_cam);
extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size);
-extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
-extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt);
extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
extern int send_control_msg(struct pwc_device *pdev,
@@ -375,9 +386,6 @@ int pwc_init_controls(struct pwc_device *pdev);
/* Power down or up the camera; not supported by all models */
extern void pwc_camera_power(struct pwc_device *pdev, int power);
-/* Private ioctl()s; see pwc-ioctl.h */
-extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
-
extern const struct v4l2_ioctl_ops pwc_ioctl_ops;
/** pwc-uncompress.c */
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 79fb22c89ae9..5a413f4427e0 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -921,12 +921,12 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
/* "Safe default" - 13MHz */
recalculate_fifo_timeout(pcdev, 13000000);
- clk_enable(pcdev->clk);
+ clk_prepare_enable(pcdev->clk);
}
static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
{
- clk_disable(pcdev->clk);
+ clk_disable_unprepare(pcdev->clk);
}
static irqreturn_t pxa_camera_irq(int irq, void *data)
@@ -1133,12 +1133,13 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
__raw_writel(cicr0, pcdev->base + CICR0);
}
-static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static int pxa_camera_set_bus_param(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct pxa_camera_dev *pcdev = ici->priv;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+ u32 pixfmt = icd->current_fmt->host_fmt->fourcc;
unsigned long bus_flags, common_flags;
int ret;
struct pxa_cam *cam = icd->host_priv;
@@ -1851,19 +1852,7 @@ static struct platform_driver pxa_camera_driver = {
.remove = __devexit_p(pxa_camera_remove),
};
-
-static int __init pxa_camera_init(void)
-{
- return platform_driver_register(&pxa_camera_driver);
-}
-
-static void __exit pxa_camera_exit(void)
-{
- platform_driver_unregister(&pxa_camera_driver);
-}
-
-module_init(pxa_camera_init);
-module_exit(pxa_camera_exit);
+module_platform_driver(pxa_camera_driver);
MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index 9937386a3bae..f6419b22c258 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -1407,18 +1407,7 @@ static struct i2c_driver rj54n1_i2c_driver = {
.id_table = rj54n1_id,
};
-static int __init rj54n1_mod_init(void)
-{
- return i2c_add_driver(&rj54n1_i2c_driver);
-}
-
-static void __exit rj54n1_mod_exit(void)
-{
- i2c_del_driver(&rj54n1_i2c_driver);
-}
-
-module_init(rj54n1_mod_init);
-module_exit(rj54n1_mod_exit);
+module_i2c_driver(rj54n1_i2c_driver);
MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver");
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index c1bef6187661..4894cbb1c547 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -134,7 +134,7 @@
/* usb config commands */
#define IN_DATA_TOKEN cpu_to_le32(0x2255c0de)
-#define CMD_2255 cpu_to_le32(0xc2255000)
+#define CMD_2255 0xc2255000
#define CMD_SET_MODE cpu_to_le32((CMD_2255 | 0x10))
#define CMD_START cpu_to_le32((CMD_2255 | 0x20))
#define CMD_STOP cpu_to_le32((CMD_2255 | 0x30))
@@ -852,15 +852,13 @@ static int vidioc_querycap(struct file *file, void *priv,
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- int index = 0;
- if (f)
- index = f->index;
+ int index = f->index;
if (index >= ARRAY_SIZE(formats))
return -EINVAL;
- if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
- (formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
- return -EINVAL;
+ if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
+ (formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
+ return -EINVAL;
dprintk(4, "name %s\n", formats[index].name);
strlcpy(f->description, formats[index].name, sizeof(f->description));
f->pixelformat = formats[index].fourcc;
@@ -2027,7 +2025,7 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
pdata[1]);
offset = jj + PREFIX_SIZE;
bframe = 1;
- cc = pdword[1];
+ cc = le32_to_cpu(pdword[1]);
if (cc >= MAX_CHANNELS) {
printk(KERN_ERR
"bad channel\n");
@@ -2036,22 +2034,22 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
/* reverse it */
dev->cc = G_chnmap[cc];
channel = &dev->channel[dev->cc];
- payload = pdword[3];
+ payload = le32_to_cpu(pdword[3]);
if (payload > channel->req_image_size) {
channel->bad_payload++;
/* discard the bad frame */
return -EINVAL;
}
channel->pkt_size = payload;
- channel->jpg_size = pdword[4];
+ channel->jpg_size = le32_to_cpu(pdword[4]);
break;
case S2255_MARKER_RESPONSE:
pdata += DEF_USB_BLOCK;
jj += DEF_USB_BLOCK;
- if (pdword[1] >= MAX_CHANNELS)
+ if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS)
break;
- cc = G_chnmap[pdword[1]];
+ cc = G_chnmap[le32_to_cpu(pdword[1])];
if (cc >= MAX_CHANNELS)
break;
channel = &dev->channel[cc];
@@ -2074,11 +2072,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
wake_up(&dev->fw_data->wait_fw);
break;
case S2255_RESPONSE_STATUS:
- channel->vidstatus = pdword[3];
+ channel->vidstatus = le32_to_cpu(pdword[3]);
channel->vidstatus_ready = 1;
wake_up(&channel->wait_vidstatus);
dprintk(5, "got vidstatus %x chan %d\n",
- pdword[3], cc);
+ le32_to_cpu(pdword[3]), cc);
break;
default:
printk(KERN_INFO "s2255 unknown resp\n");
@@ -2605,10 +2603,11 @@ static int s2255_probe(struct usb_interface *interface,
__le32 *pRel;
pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel);
- dev->dsp_fw_ver = *pRel;
- if (*pRel < S2255_CUR_DSP_FWVER)
+ dev->dsp_fw_ver = le32_to_cpu(*pRel);
+ if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER)
printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
- if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER)
+ if (dev->pid == 0x2257 &&
+ dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
printk(KERN_WARNING "s2255: 2257 requires firmware %d"
" or above.\n", S2255_MIN_DSP_COLORFILTER);
}
diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c
index 0df7f2a41814..6625e46a4638 100644
--- a/drivers/media/video/s5k6aa.c
+++ b/drivers/media/video/s5k6aa.c
@@ -1582,8 +1582,8 @@ static int s5k6aa_probe(struct i2c_client *client,
s5k6aa->inv_vflip = pdata->vert_flip;
sd = &s5k6aa->sd;
- strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops);
+ strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
sd->internal_ops = &s5k6aa_subdev_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -1663,18 +1663,7 @@ static struct i2c_driver s5k6aa_i2c_driver = {
.id_table = s5k6aa_id,
};
-static int __init s5k6aa_init(void)
-{
- return i2c_add_driver(&s5k6aa_i2c_driver);
-}
-
-static void __exit s5k6aa_exit(void)
-{
- i2c_del_driver(&s5k6aa_i2c_driver);
-}
-
-module_init(s5k6aa_init);
-module_exit(s5k6aa_exit);
+module_i2c_driver(s5k6aa_i2c_driver);
MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index 2cc3b9166724..b06efd208328 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -63,6 +63,8 @@ static int fimc_init_capture(struct fimc_dev *fimc)
fimc_hw_set_effect(ctx, false);
fimc_hw_set_output_path(ctx);
fimc_hw_set_out_dma(ctx);
+ if (fimc->variant->has_alpha)
+ fimc_hw_set_rgb_alpha(ctx);
clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
}
spin_unlock_irqrestore(&fimc->slock, flags);
@@ -154,6 +156,8 @@ int fimc_capture_config_update(struct fimc_ctx *ctx)
fimc_hw_set_rotation(ctx);
fimc_prepare_dma_offset(ctx, &ctx->d_frame);
fimc_hw_set_out_dma(ctx);
+ if (fimc->variant->has_alpha)
+ fimc_hw_set_rgb_alpha(ctx);
clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
}
spin_unlock(&ctx->slock);
@@ -689,7 +693,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
mf->code = 0;
continue;
}
- if (mf->width != tfmt->width || mf->width != tfmt->width) {
+ if (mf->width != tfmt->width || mf->height != tfmt->height) {
u32 fcc = ffmt->fourcc;
tfmt->width = mf->width;
tfmt->height = mf->height;
@@ -698,7 +702,8 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
NULL, &fcc, FIMC_SD_PAD_SOURCE);
if (ffmt && ffmt->mbus_code)
mf->code = ffmt->mbus_code;
- if (mf->width != tfmt->width || mf->width != tfmt->width)
+ if (mf->width != tfmt->width ||
+ mf->height != tfmt->height)
continue;
tfmt->code = mf->code;
}
@@ -706,7 +711,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
ret = v4l2_subdev_call(csis, pad, set_fmt, NULL, &sfmt);
if (mf->code == tfmt->code &&
- mf->width == tfmt->width && mf->width == tfmt->width)
+ mf->width == tfmt->width && mf->height == tfmt->height)
break;
}
@@ -812,6 +817,10 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
FIMC_SD_PAD_SOURCE);
if (!ff->fmt)
return -EINVAL;
+
+ /* Update RGB Alpha control state and value range */
+ fimc_alpha_ctrl_update(ctx);
+
/* Try to match format at the host and the sensor */
if (!fimc->vid_cap.user_subdev_api) {
mf->code = ff->fmt->mbus_code;
@@ -1010,52 +1019,117 @@ static int fimc_cap_dqbuf(struct file *file, void *priv,
return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK);
}
-static int fimc_cap_cropcap(struct file *file, void *fh,
- struct v4l2_cropcap *cr)
+static int fimc_cap_create_bufs(struct file *file, void *priv,
+ struct v4l2_create_buffers *create)
{
struct fimc_dev *fimc = video_drvdata(file);
- struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
- if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return -EINVAL;
+ return vb2_create_bufs(&fimc->vid_cap.vbq, create);
+}
- cr->bounds.left = 0;
- cr->bounds.top = 0;
- cr->bounds.width = f->o_width;
- cr->bounds.height = f->o_height;
- cr->defrect = cr->bounds;
+static int fimc_cap_prepare_buf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
- return 0;
+ return vb2_prepare_buf(&fimc->vid_cap.vbq, b);
}
-static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+static int fimc_cap_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
{
struct fimc_dev *fimc = video_drvdata(file);
- struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
+ struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+ struct fimc_frame *f = &ctx->s_frame;
- cr->c.left = f->offs_h;
- cr->c.top = f->offs_v;
- cr->c.width = f->width;
- cr->c.height = f->height;
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
- return 0;
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ f = &ctx->d_frame;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = f->o_width;
+ s->r.height = f->o_height;
+ return 0;
+
+ case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+ f = &ctx->d_frame;
+ case V4L2_SEL_TGT_CROP_ACTIVE:
+ s->r.left = f->offs_h;
+ s->r.top = f->offs_v;
+ s->r.width = f->width;
+ s->r.height = f->height;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
+int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+ if (a->left < b->left || a->top < b->top)
+ return 0;
+ if (a->left + a->width > b->left + b->width)
+ return 0;
+ if (a->top + a->height > b->top + b->height)
+ return 0;
+
+ return 1;
}
-static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+static int fimc_cap_s_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
{
struct fimc_dev *fimc = video_drvdata(file);
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
- struct fimc_frame *ff;
+ struct v4l2_rect rect = s->r;
+ struct fimc_frame *f;
unsigned long flags;
+ unsigned int pad;
- fimc_capture_try_crop(ctx, &cr->c, FIMC_SD_PAD_SINK);
- ff = &ctx->s_frame;
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+ f = &ctx->d_frame;
+ pad = FIMC_SD_PAD_SOURCE;
+ break;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_ACTIVE:
+ f = &ctx->s_frame;
+ pad = FIMC_SD_PAD_SINK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ fimc_capture_try_crop(ctx, &rect, pad);
+
+ if (s->flags & V4L2_SEL_FLAG_LE &&
+ !enclosed_rectangle(&rect, &s->r))
+ return -ERANGE;
+
+ if (s->flags & V4L2_SEL_FLAG_GE &&
+ !enclosed_rectangle(&s->r, &rect))
+ return -ERANGE;
+
+ s->r = rect;
spin_lock_irqsave(&fimc->slock, flags);
- set_frame_crop(ff, cr->c.left, cr->c.top, cr->c.width, cr->c.height);
- set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+ set_frame_crop(f, s->r.left, s->r.top, s->r.width,
+ s->r.height);
spin_unlock_irqrestore(&fimc->slock, flags);
+ set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
return 0;
}
@@ -1073,12 +1147,14 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
.vidioc_qbuf = fimc_cap_qbuf,
.vidioc_dqbuf = fimc_cap_dqbuf,
+ .vidioc_prepare_buf = fimc_cap_prepare_buf,
+ .vidioc_create_bufs = fimc_cap_create_bufs,
+
.vidioc_streamon = fimc_cap_streamon,
.vidioc_streamoff = fimc_cap_streamoff,
- .vidioc_g_crop = fimc_cap_g_crop,
- .vidioc_s_crop = fimc_cap_s_crop,
- .vidioc_cropcap = fimc_cap_cropcap,
+ .vidioc_g_selection = fimc_cap_g_selection,
+ .vidioc_s_selection = fimc_cap_s_selection,
.vidioc_enum_input = fimc_cap_enum_input,
.vidioc_s_input = fimc_cap_s_input,
@@ -1235,6 +1311,9 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
*mf = fmt->format;
return 0;
}
+ /* Update RGB Alpha control state and value range */
+ fimc_alpha_ctrl_update(ctx);
+
fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color));
ff = fmt->pad == FIMC_SD_PAD_SINK ?
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 07c6254faee3..e184e650022a 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -52,13 +52,29 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 1,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "XRGB-8-8-8-8, 32 bpp",
+ .name = "ARGB8888, 32 bpp",
.fourcc = V4L2_PIX_FMT_RGB32,
.depth = { 32 },
.color = S5P_FIMC_RGB888,
.memplanes = 1,
.colplanes = 1,
- .flags = FMT_FLAGS_M2M,
+ .flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA,
+ }, {
+ .name = "ARGB1555",
+ .fourcc = V4L2_PIX_FMT_RGB555,
+ .depth = { 16 },
+ .color = S5P_FIMC_RGB555,
+ .memplanes = 1,
+ .colplanes = 1,
+ .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
+ }, {
+ .name = "ARGB4444",
+ .fourcc = V4L2_PIX_FMT_RGB444,
+ .depth = { 16 },
+ .color = S5P_FIMC_RGB444,
+ .memplanes = 1,
+ .colplanes = 1,
+ .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
}, {
.name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
@@ -171,6 +187,14 @@ static struct fimc_fmt fimc_formats[] = {
},
};
+static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
+{
+ if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return FMT_FLAGS_M2M_IN;
+ else
+ return FMT_FLAGS_M2M_OUT;
+}
+
int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
int dw, int dh, int rotation)
{
@@ -652,8 +676,11 @@ static void fimc_dma_run(void *priv)
if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS))
fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1);
- if (ctx->state & FIMC_PARAMS)
+ if (ctx->state & FIMC_PARAMS) {
fimc_hw_set_out_dma(ctx);
+ if (fimc->variant->has_alpha)
+ fimc_hw_set_rgb_alpha(ctx);
+ }
fimc_activate_capture(ctx);
@@ -750,12 +777,11 @@ static struct vb2_ops fimc_qops = {
#define ctrl_to_ctx(__ctrl) \
container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler)
-static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
+static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
{
- struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
struct fimc_dev *fimc = ctx->fimc_dev;
struct samsung_fimc_variant *variant = fimc->variant;
- unsigned long flags;
+ unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT;
int ret = 0;
if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
@@ -763,59 +789,77 @@ static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_HFLIP:
- spin_lock_irqsave(&ctx->slock, flags);
ctx->hflip = ctrl->val;
break;
case V4L2_CID_VFLIP:
- spin_lock_irqsave(&ctx->slock, flags);
ctx->vflip = ctrl->val;
break;
case V4L2_CID_ROTATE:
if (fimc_capture_pending(fimc) ||
- fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
+ (ctx->state & flags) == flags) {
ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
ctx->s_frame.height, ctx->d_frame.width,
ctx->d_frame.height, ctrl->val);
- }
- if (ret) {
- v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
- return -EINVAL;
+ if (ret)
+ return -EINVAL;
}
if ((ctrl->val == 90 || ctrl->val == 270) &&
!variant->has_out_rot)
return -EINVAL;
- spin_lock_irqsave(&ctx->slock, flags);
+
ctx->rotation = ctrl->val;
break;
- default:
- v4l2_err(fimc->v4l2_dev, "Invalid control: 0x%X\n", ctrl->id);
- return -EINVAL;
+ case V4L2_CID_ALPHA_COMPONENT:
+ ctx->d_frame.alpha = ctrl->val;
+ break;
}
ctx->state |= FIMC_PARAMS;
set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
- spin_unlock_irqrestore(&ctx->slock, flags);
return 0;
}
+static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ ret = __fimc_s_ctrl(ctx, ctrl);
+ spin_unlock_irqrestore(&ctx->slock, flags);
+
+ return ret;
+}
+
static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
.s_ctrl = fimc_s_ctrl,
};
int fimc_ctrls_create(struct fimc_ctx *ctx)
{
+ struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+ unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
+
if (ctx->ctrls_rdy)
return 0;
- v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
+ V4L2_CID_ROTATE, 0, 270, 90, 0);
ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
- V4L2_CID_ROTATE, 0, 270, 90, 0);
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (variant->has_alpha)
+ ctx->ctrl_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+ &fimc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
+ 0, max_alpha, 1, 0);
+ else
+ ctx->ctrl_alpha = NULL;
+
ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
return ctx->ctrl_handler.error;
@@ -826,11 +870,14 @@ void fimc_ctrls_delete(struct fimc_ctx *ctx)
if (ctx->ctrls_rdy) {
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
ctx->ctrls_rdy = false;
+ ctx->ctrl_alpha = NULL;
}
}
void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
{
+ unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
+
if (!ctx->ctrls_rdy)
return;
@@ -838,6 +885,8 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
v4l2_ctrl_activate(ctx->ctrl_rotate, active);
v4l2_ctrl_activate(ctx->ctrl_hflip, active);
v4l2_ctrl_activate(ctx->ctrl_vflip, active);
+ if (ctx->ctrl_alpha)
+ v4l2_ctrl_activate(ctx->ctrl_alpha, active && has_alpha);
if (active) {
ctx->rotation = ctx->ctrl_rotate->val;
@@ -851,6 +900,24 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
mutex_unlock(&ctx->ctrl_handler.lock);
}
+/* Update maximum value of the alpha color control */
+void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct v4l2_ctrl *ctrl = ctx->ctrl_alpha;
+
+ if (ctrl == NULL || !fimc->variant->has_alpha)
+ return;
+
+ v4l2_ctrl_lock(ctrl);
+ ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt);
+
+ if (ctrl->cur.val > ctrl->maximum)
+ ctrl->cur.val = ctrl->maximum;
+
+ v4l2_ctrl_unlock(ctrl);
+}
+
/*
* V4L2 ioctl handlers
*/
@@ -874,7 +941,8 @@ static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
{
struct fimc_fmt *fmt;
- fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_M2M, f->index);
+ fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
+ f->index);
if (!fmt)
return -EINVAL;
@@ -938,6 +1006,7 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
pix->colorspace = V4L2_COLORSPACE_JPEG;
pix->field = V4L2_FIELD_NONE;
pix->num_planes = fmt->memplanes;
+ pix->pixelformat = fmt->fourcc;
pix->height = height;
pix->width = width;
@@ -1017,7 +1086,8 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
dbg("w: %d, h: %d", pix->width, pix->height);
- fmt = fimc_find_format(&pix->pixelformat, NULL, FMT_FLAGS_M2M, 0);
+ fmt = fimc_find_format(&pix->pixelformat, NULL,
+ get_m2m_fmt_flags(f->type), 0);
if (WARN(fmt == NULL, "Pixel format lookup failed"))
return -EINVAL;
@@ -1087,10 +1157,13 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
pix = &f->fmt.pix_mp;
frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
- FMT_FLAGS_M2M, 0);
+ get_m2m_fmt_flags(f->type), 0);
if (!frame->fmt)
return -EINVAL;
+ /* Update RGB Alpha control state and value range */
+ fimc_alpha_ctrl_update(ctx);
+
for (i = 0; i < frame->fmt->colplanes; i++) {
frame->payload[i] =
(pix->width * pix->height * frame->fmt->depth[i]) / 8;
@@ -1374,6 +1447,12 @@ static int fimc_m2m_open(struct file *file)
if (!ctx)
return -ENOMEM;
v4l2_fh_init(&ctx->fh, fimc->m2m.vfd);
+ ctx->fimc_dev = fimc;
+
+ /* Default color format */
+ ctx->s_frame.fmt = &fimc_formats[0];
+ ctx->d_frame.fmt = &fimc_formats[0];
+
ret = fimc_ctrls_create(ctx);
if (ret)
goto error_fh;
@@ -1383,10 +1462,6 @@ static int fimc_m2m_open(struct file *file)
file->private_data = &ctx->fh;
v4l2_fh_add(&ctx->fh);
- ctx->fimc_dev = fimc;
- /* Default color format */
- ctx->s_frame.fmt = &fimc_formats[0];
- ctx->d_frame.fmt = &fimc_formats[0];
/* Setup the device context for memory-to-memory mode */
ctx->state = FIMC_CTX_M2M;
ctx->flags = 0;
@@ -1527,24 +1602,35 @@ static void fimc_clk_put(struct fimc_dev *fimc)
{
int i;
for (i = 0; i < fimc->num_clocks; i++) {
- if (fimc->clock[i])
- clk_put(fimc->clock[i]);
+ if (IS_ERR_OR_NULL(fimc->clock[i]))
+ continue;
+ clk_unprepare(fimc->clock[i]);
+ clk_put(fimc->clock[i]);
+ fimc->clock[i] = NULL;
}
}
static int fimc_clk_get(struct fimc_dev *fimc)
{
- int i;
+ int i, ret;
+
for (i = 0; i < fimc->num_clocks; i++) {
fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
- if (!IS_ERR_OR_NULL(fimc->clock[i]))
- continue;
- dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n",
- fimc_clocks[i]);
- return -ENXIO;
+ if (IS_ERR(fimc->clock[i]))
+ goto err;
+ ret = clk_prepare(fimc->clock[i]);
+ if (ret < 0) {
+ clk_put(fimc->clock[i]);
+ fimc->clock[i] = NULL;
+ goto err;
+ }
}
-
return 0;
+err:
+ fimc_clk_put(fimc);
+ dev_err(&fimc->pdev->dev, "failed to get clock: %s\n",
+ fimc_clocks[i]);
+ return -ENXIO;
}
static int fimc_m2m_suspend(struct fimc_dev *fimc)
@@ -1592,8 +1678,6 @@ static int fimc_probe(struct platform_device *pdev)
struct s5p_platform_fimc *pdata;
int ret = 0;
- dev_dbg(&pdev->dev, "%s():\n", __func__);
-
drv_data = (struct samsung_fimc_driverdata *)
platform_get_device_id(pdev)->driver_data;
@@ -1603,7 +1687,7 @@ static int fimc_probe(struct platform_device *pdev)
return -EINVAL;
}
- fimc = kzalloc(sizeof(struct fimc_dev), GFP_KERNEL);
+ fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
if (!fimc)
return -ENOMEM;
@@ -1614,51 +1698,35 @@ static int fimc_probe(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
fimc->pdata = pdata;
-
init_waitqueue_head(&fimc->irq_queue);
spin_lock_init(&fimc->slock);
mutex_init(&fimc->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "failed to find the registers\n");
- ret = -ENOENT;
- goto err_info;
- }
-
- fimc->regs_res = request_mem_region(res->start, resource_size(res),
- dev_name(&pdev->dev));
- if (!fimc->regs_res) {
- dev_err(&pdev->dev, "failed to obtain register region\n");
- ret = -ENOENT;
- goto err_info;
- }
-
- fimc->regs = ioremap(res->start, resource_size(res));
- if (!fimc->regs) {
- dev_err(&pdev->dev, "failed to map registers\n");
- ret = -ENXIO;
- goto err_req_region;
+ fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (fimc->regs == NULL) {
+ dev_err(&pdev->dev, "Failed to obtain io memory\n");
+ return -ENOENT;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_err(&pdev->dev, "failed to get IRQ resource\n");
- ret = -ENXIO;
- goto err_regs_unmap;
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Failed to get IRQ resource\n");
+ return -ENXIO;
}
fimc->irq = res->start;
fimc->num_clocks = MAX_FIMC_CLOCKS;
ret = fimc_clk_get(fimc);
if (ret)
- goto err_regs_unmap;
+ return ret;
clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
clk_enable(fimc->clock[CLK_BUS]);
platform_set_drvdata(pdev, fimc);
- ret = request_irq(fimc->irq, fimc_irq_handler, 0, pdev->name, fimc);
+ ret = devm_request_irq(&pdev->dev, fimc->irq, fimc_irq_handler,
+ 0, pdev->name, fimc);
if (ret) {
dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
goto err_clk;
@@ -1667,7 +1735,7 @@ static int fimc_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
- goto err_irq;
+ goto err_clk;
/* Initialize contiguous memory allocator */
fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(fimc->alloc_ctx)) {
@@ -1682,17 +1750,8 @@ static int fimc_probe(struct platform_device *pdev)
err_pm:
pm_runtime_put(&pdev->dev);
-err_irq:
- free_irq(fimc->irq, fimc);
err_clk:
fimc_clk_put(fimc);
-err_regs_unmap:
- iounmap(fimc->regs);
-err_req_region:
- release_resource(fimc->regs_res);
- kfree(fimc->regs_res);
-err_info:
- kfree(fimc);
return ret;
}
@@ -1709,9 +1768,8 @@ static int fimc_runtime_resume(struct device *dev)
/* Resume the capture or mem-to-mem device */
if (fimc_capture_busy(fimc))
return fimc_capture_resume(fimc);
- else if (fimc_m2m_pending(fimc))
- return fimc_m2m_resume(fimc);
- return 0;
+
+ return fimc_m2m_resume(fimc);
}
static int fimc_runtime_suspend(struct device *dev)
@@ -1780,11 +1838,6 @@ static int __devexit fimc_remove(struct platform_device *pdev)
clk_disable(fimc->clock[CLK_BUS]);
fimc_clk_put(fimc);
- free_irq(fimc->irq, fimc);
- iounmap(fimc->regs);
- release_resource(fimc->regs_res);
- kfree(fimc->regs_res);
- kfree(fimc);
dev_info(&pdev->dev, "driver unloaded\n");
return 0;
@@ -1893,6 +1946,7 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = {
.has_cam_if = 1,
.has_cistatus2 = 1,
.has_mainscaler_ext = 1,
+ .has_alpha = 1,
.min_inp_pixsize = 16,
.min_out_pixsize = 16,
.hor_offs_align = 2,
@@ -1906,6 +1960,7 @@ static struct samsung_fimc_variant fimc3_variant_exynos4 = {
.has_cam_if = 1,
.has_cistatus2 = 1,
.has_mainscaler_ext = 1,
+ .has_alpha = 1,
.min_inp_pixsize = 16,
.min_out_pixsize = 16,
.hor_offs_align = 2,
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index c7f01c47b20f..a18291e648e2 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -85,7 +85,9 @@ enum fimc_datapath {
};
enum fimc_color_fmt {
- S5P_FIMC_RGB565 = 0x10,
+ S5P_FIMC_RGB444 = 0x10,
+ S5P_FIMC_RGB555,
+ S5P_FIMC_RGB565,
S5P_FIMC_RGB666,
S5P_FIMC_RGB888,
S5P_FIMC_RGB30_LOCAL,
@@ -160,8 +162,11 @@ struct fimc_fmt {
u16 colplanes;
u8 depth[VIDEO_MAX_PLANES];
u16 flags;
-#define FMT_FLAGS_CAM (1 << 0)
-#define FMT_FLAGS_M2M (1 << 1)
+#define FMT_FLAGS_CAM (1 << 0)
+#define FMT_FLAGS_M2M_IN (1 << 1)
+#define FMT_FLAGS_M2M_OUT (1 << 2)
+#define FMT_FLAGS_M2M (1 << 1 | 1 << 2)
+#define FMT_HAS_ALPHA (1 << 3)
};
/**
@@ -283,6 +288,7 @@ struct fimc_frame {
struct fimc_addr paddr;
struct fimc_dma_offset dma_offset;
struct fimc_fmt *fmt;
+ u8 alpha;
};
/**
@@ -387,6 +393,7 @@ struct samsung_fimc_variant {
unsigned int has_cistatus2:1;
unsigned int has_mainscaler_ext:1;
unsigned int has_cam_if:1;
+ unsigned int has_alpha:1;
struct fimc_pix_limit *pix_limit;
u16 min_inp_pixsize;
u16 min_out_pixsize;
@@ -427,7 +434,6 @@ struct fimc_ctx;
* @num_clocks: the number of clocks managed by this device instance
* @clock: clocks required for FIMC operation
* @regs: the mapped hardware registers
- * @regs_res: the resource claimed for IO registers
* @irq: FIMC interrupt number
* @irq_queue: interrupt handler waitqueue
* @v4l2_dev: root v4l2_device
@@ -447,7 +453,6 @@ struct fimc_dev {
u16 num_clocks;
struct clk *clock[MAX_FIMC_CLOCKS];
void __iomem *regs;
- struct resource *regs_res;
int irq;
wait_queue_head_t irq_queue;
struct v4l2_device *v4l2_dev;
@@ -482,7 +487,8 @@ struct fimc_dev {
* @ctrl_handler: v4l2 controls handler
* @ctrl_rotate image rotation control
* @ctrl_hflip horizontal flip control
- * @ctrl_vflip vartical flip control
+ * @ctrl_vflip vertical flip control
+ * @ctrl_alpha RGB alpha control
* @ctrls_rdy: true if the control handler is initialized
*/
struct fimc_ctx {
@@ -509,6 +515,7 @@ struct fimc_ctx {
struct v4l2_ctrl *ctrl_rotate;
struct v4l2_ctrl *ctrl_hflip;
struct v4l2_ctrl *ctrl_vflip;
+ struct v4l2_ctrl *ctrl_alpha;
bool ctrls_rdy;
};
@@ -578,6 +585,17 @@ static inline int tiled_fmt(struct fimc_fmt *fmt)
return fmt->fourcc == V4L2_PIX_FMT_NV12MT;
}
+/* Return the alpha component bit mask */
+static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt)
+{
+ switch (fmt->color) {
+ case S5P_FIMC_RGB444: return 0x0f;
+ case S5P_FIMC_RGB555: return 0x01;
+ case S5P_FIMC_RGB888: return 0xff;
+ default: return 0;
+ };
+}
+
static inline void fimc_hw_clear_irq(struct fimc_dev *dev)
{
u32 cfg = readl(dev->regs + S5P_CIGCTRL);
@@ -674,6 +692,7 @@ void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
void fimc_hw_en_capture(struct fimc_ctx *ctx);
void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active);
+void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx);
void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
void fimc_hw_set_input_path(struct fimc_ctx *ctx);
void fimc_hw_set_output_path(struct fimc_ctx *ctx);
@@ -695,6 +714,7 @@ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
int fimc_ctrls_create(struct fimc_ctx *ctx);
void fimc_ctrls_delete(struct fimc_ctx *ctx);
void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
+void fimc_alpha_ctrl_update(struct fimc_ctx *ctx);
int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f);
void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
struct v4l2_pix_format_mplane *pix);
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
index 615c862f0360..62ed37e40149 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c
@@ -21,7 +21,6 @@
#include <linux/pm_runtime.h>
#include <linux/types.h>
#include <linux/slab.h>
-#include <linux/version.h>
#include <media/v4l2-ctrls.h>
#include <media/media-device.h>
@@ -345,16 +344,13 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd)
return -ENODEV;
ret = driver_for_each_device(driver, NULL, fmd,
fimc_register_callback);
- put_driver(driver);
if (ret)
return ret;
driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
- if (driver) {
+ if (driver)
ret = driver_for_each_device(driver, NULL, fmd,
csis_register_callback);
- put_driver(driver);
- }
return ret;
}
@@ -754,7 +750,7 @@ static int __devinit fimc_md_probe(struct platform_device *pdev)
struct fimc_md *fmd;
int ret;
- fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL);
+ fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL);
if (!fmd)
return -ENOMEM;
@@ -775,7 +771,7 @@ static int __devinit fimc_md_probe(struct platform_device *pdev)
ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
- goto err1;
+ return ret;
}
ret = media_device_register(&fmd->media_dev);
if (ret < 0) {
@@ -817,8 +813,6 @@ err3:
fimc_md_unregister_entities(fmd);
err2:
v4l2_device_unregister(&fmd->v4l2_dev);
-err1:
- kfree(fmd);
return ret;
}
@@ -832,7 +826,6 @@ static int __devexit fimc_md_remove(struct platform_device *pdev)
fimc_md_unregister_entities(fmd);
media_device_unregister(&fmd->media_dev);
fimc_md_put_clocks(fmd);
- kfree(fmd);
return 0;
}
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 44f5c2d1920b..15466d0529c1 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -117,7 +117,7 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx)
S5P_CITRGFMT_VSIZE_MASK);
switch (frame->fmt->color) {
- case S5P_FIMC_RGB565...S5P_FIMC_RGB888:
+ case S5P_FIMC_RGB444...S5P_FIMC_RGB888:
cfg |= S5P_CITRGFMT_RGB;
break;
case S5P_FIMC_YCBCR420:
@@ -175,6 +175,7 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
struct fimc_dev *dev = ctx->fimc_dev;
struct fimc_frame *frame = &ctx->d_frame;
struct fimc_dma_offset *offset = &frame->dma_offset;
+ struct fimc_fmt *fmt = frame->fmt;
/* Set the input dma offsets. */
cfg = 0;
@@ -198,15 +199,22 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
cfg = readl(dev->regs + S5P_CIOCTRL);
cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK |
- S5P_CIOCTRL_YCBCR_PLANE_MASK);
+ S5P_CIOCTRL_YCBCR_PLANE_MASK | S5P_CIOCTRL_RGB16FMT_MASK);
- if (frame->fmt->colplanes == 1)
+ if (fmt->colplanes == 1)
cfg |= ctx->out_order_1p;
- else if (frame->fmt->colplanes == 2)
+ else if (fmt->colplanes == 2)
cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE;
- else if (frame->fmt->colplanes == 3)
+ else if (fmt->colplanes == 3)
cfg |= S5P_CIOCTRL_YCBCR_3PLANE;
+ if (fmt->color == S5P_FIMC_RGB565)
+ cfg |= S5P_CIOCTRL_RGB565;
+ else if (fmt->color == S5P_FIMC_RGB555)
+ cfg |= S5P_CIOCTRL_ARGB1555;
+ else if (fmt->color == S5P_FIMC_RGB444)
+ cfg |= S5P_CIOCTRL_ARGB4444;
+
writel(cfg, dev->regs + S5P_CIOCTRL);
}
@@ -278,22 +286,28 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
if (sc->copy_mode)
cfg |= S5P_CISCCTRL_ONE2ONE;
-
if (ctx->in_path == FIMC_DMA) {
- if (src_frame->fmt->color == S5P_FIMC_RGB565)
+ switch (src_frame->fmt->color) {
+ case S5P_FIMC_RGB565:
cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565;
- else if (src_frame->fmt->color == S5P_FIMC_RGB666)
+ break;
+ case S5P_FIMC_RGB666:
cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666;
- else if (src_frame->fmt->color == S5P_FIMC_RGB888)
+ break;
+ case S5P_FIMC_RGB888:
cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888;
+ break;
+ }
}
if (ctx->out_path == FIMC_DMA) {
- if (dst_frame->fmt->color == S5P_FIMC_RGB565)
+ u32 color = dst_frame->fmt->color;
+
+ if (color >= S5P_FIMC_RGB444 && color <= S5P_FIMC_RGB565)
cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565;
- else if (dst_frame->fmt->color == S5P_FIMC_RGB666)
+ else if (color == S5P_FIMC_RGB666)
cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666;
- else if (dst_frame->fmt->color == S5P_FIMC_RGB888)
+ else if (color == S5P_FIMC_RGB888)
cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
} else {
cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
@@ -379,6 +393,21 @@ void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active)
writel(cfg, dev->regs + S5P_CIIMGEFF);
}
+void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *dev = ctx->fimc_dev;
+ struct fimc_frame *frame = &ctx->d_frame;
+ u32 cfg;
+
+ if (!(frame->fmt->flags & FMT_HAS_ALPHA))
+ return;
+
+ cfg = readl(dev->regs + S5P_CIOCTRL);
+ cfg &= ~S5P_CIOCTRL_ALPHA_OUT_MASK;
+ cfg |= (frame->alpha << 4);
+ writel(cfg, dev->regs + S5P_CIOCTRL);
+}
+
static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c
index 59d79bc2f58a..f44f690397f7 100644
--- a/drivers/media/video/s5p-fimc/mipi-csis.c
+++ b/drivers/media/video/s5p-fimc/mipi-csis.c
@@ -1,8 +1,8 @@
/*
* Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
*
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki, <s.nawrocki@samsung.com>
*
* 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
@@ -100,7 +100,6 @@ enum {
* @pads: CSIS pads array
* @sd: v4l2_subdev associated with CSIS device instance
* @pdev: CSIS platform device
- * @regs_res: requested I/O register memory resource
* @regs: mmaped I/O registers memory
* @clock: CSIS clocks
* @irq: requested s5p-mipi-csis irq number
@@ -113,7 +112,6 @@ struct csis_state {
struct media_pad pads[CSIS_PADS_NUM];
struct v4l2_subdev sd;
struct platform_device *pdev;
- struct resource *regs_res;
void __iomem *regs;
struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
struct clk *clock[NUM_CSIS_CLOCKS];
@@ -258,26 +256,36 @@ static void s5pcsis_clk_put(struct csis_state *state)
{
int i;
- for (i = 0; i < NUM_CSIS_CLOCKS; i++)
- if (!IS_ERR_OR_NULL(state->clock[i]))
- clk_put(state->clock[i]);
+ for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
+ if (IS_ERR_OR_NULL(state->clock[i]))
+ continue;
+ clk_unprepare(state->clock[i]);
+ clk_put(state->clock[i]);
+ state->clock[i] = NULL;
+ }
}
static int s5pcsis_clk_get(struct csis_state *state)
{
struct device *dev = &state->pdev->dev;
- int i;
+ int i, ret;
for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
state->clock[i] = clk_get(dev, csi_clock_name[i]);
- if (IS_ERR(state->clock[i])) {
- s5pcsis_clk_put(state);
- dev_err(dev, "failed to get clock: %s\n",
- csi_clock_name[i]);
- return -ENXIO;
+ if (IS_ERR(state->clock[i]))
+ goto err;
+ ret = clk_prepare(state->clock[i]);
+ if (ret < 0) {
+ clk_put(state->clock[i]);
+ state->clock[i] = NULL;
+ goto err;
}
}
return 0;
+err:
+ s5pcsis_clk_put(state);
+ dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]);
+ return -ENXIO;
}
static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
@@ -427,6 +435,23 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
return 0;
}
+static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+
+ format->colorspace = V4L2_COLORSPACE_JPEG;
+ format->code = s5pcsis_formats[0].code;
+ format->width = S5PCSIS_DEF_PIX_WIDTH;
+ format->height = S5PCSIS_DEF_PIX_HEIGHT;
+ format->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops s5pcsis_sd_internal_ops = {
+ .open = s5pcsis_open,
+};
+
static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
.s_power = s5pcsis_s_power,
};
@@ -463,12 +488,11 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
{
struct s5p_platform_mipi_csis *pdata;
struct resource *mem_res;
- struct resource *regs_res;
struct csis_state *state;
int ret = -ENOMEM;
int i;
- state = kzalloc(sizeof(*state), GFP_KERNEL);
+ state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
@@ -478,52 +502,27 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
if (pdata == NULL || pdata->phy_enable == NULL) {
dev_err(&pdev->dev, "Platform data not fully specified\n");
- goto e_free;
+ return -EINVAL;
}
if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
pdata->lanes > CSIS0_MAX_LANES) {
- ret = -EINVAL;
dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
pdata->lanes);
- goto e_free;
+ return -EINVAL;
}
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- dev_err(&pdev->dev, "Failed to get IO memory region\n");
- goto e_free;
+ state->regs = devm_request_and_ioremap(&pdev->dev, mem_res);
+ if (state->regs == NULL) {
+ dev_err(&pdev->dev, "Failed to request and remap io memory\n");
+ return -ENXIO;
}
- regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
- pdev->name);
- if (!regs_res) {
- dev_err(&pdev->dev, "Failed to request IO memory region\n");
- goto e_free;
- }
- state->regs_res = regs_res;
-
- state->regs = ioremap(mem_res->start, resource_size(mem_res));
- if (!state->regs) {
- dev_err(&pdev->dev, "Failed to remap IO region\n");
- goto e_reqmem;
- }
-
- ret = s5pcsis_clk_get(state);
- if (ret)
- goto e_unmap;
-
- clk_enable(state->clock[CSIS_CLK_MUX]);
- if (pdata->clk_rate)
- clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
- else
- dev_WARN(&pdev->dev, "No clock frequency specified!\n");
-
state->irq = platform_get_irq(pdev, 0);
if (state->irq < 0) {
- ret = state->irq;
dev_err(&pdev->dev, "Failed to get irq\n");
- goto e_clkput;
+ return state->irq;
}
for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
@@ -532,26 +531,41 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
state->supplies);
if (ret)
+ return ret;
+
+ ret = s5pcsis_clk_get(state);
+ if (ret)
goto e_clkput;
- ret = request_irq(state->irq, s5pcsis_irq_handler, 0,
- dev_name(&pdev->dev), state);
+ clk_enable(state->clock[CSIS_CLK_MUX]);
+ if (pdata->clk_rate)
+ clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
+ else
+ dev_WARN(&pdev->dev, "No clock frequency specified!\n");
+
+ ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler,
+ 0, dev_name(&pdev->dev), state);
if (ret) {
- dev_err(&pdev->dev, "request_irq failed\n");
+ dev_err(&pdev->dev, "Interrupt request failed\n");
goto e_regput;
}
v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
state->sd.owner = THIS_MODULE;
strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name));
+ state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
state->csis_fmt = &s5pcsis_formats[0];
+ state->format.code = s5pcsis_formats[0].code;
+ state->format.width = S5PCSIS_DEF_PIX_WIDTH;
+ state->format.height = S5PCSIS_DEF_PIX_HEIGHT;
+
state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_init(&state->sd.entity,
CSIS_PADS_NUM, state->pads, 0);
if (ret < 0)
- goto e_irqfree;
+ goto e_clkput;
/* This allows to retrieve the platform device id by the host driver */
v4l2_set_subdevdata(&state->sd, pdev);
@@ -560,22 +574,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &state->sd);
pm_runtime_enable(&pdev->dev);
-
return 0;
-e_irqfree:
- free_irq(state->irq, state);
e_regput:
regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
e_clkput:
clk_disable(state->clock[CSIS_CLK_MUX]);
s5pcsis_clk_put(state);
-e_unmap:
- iounmap(state->regs);
-e_reqmem:
- release_mem_region(regs_res->start, resource_size(regs_res));
-e_free:
- kfree(state);
return ret;
}
@@ -677,21 +682,15 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev)
{
struct v4l2_subdev *sd = platform_get_drvdata(pdev);
struct csis_state *state = sd_to_csis_state(sd);
- struct resource *res = state->regs_res;
pm_runtime_disable(&pdev->dev);
- s5pcsis_suspend(&pdev->dev);
+ s5pcsis_pm_suspend(&pdev->dev, false);
clk_disable(state->clock[CSIS_CLK_MUX]);
pm_runtime_set_suspended(&pdev->dev);
-
s5pcsis_clk_put(state);
regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
media_entity_cleanup(&state->sd.entity);
- free_irq(state->irq, state);
- iounmap(state->regs);
- release_mem_region(res->start, resource_size(res));
- kfree(state);
return 0;
}
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.h b/drivers/media/video/s5p-fimc/mipi-csis.h
index f5691336dd5c..2709286396e1 100644
--- a/drivers/media/video/s5p-fimc/mipi-csis.h
+++ b/drivers/media/video/s5p-fimc/mipi-csis.h
@@ -19,4 +19,7 @@
#define CSIS_PAD_SOURCE 1
#define CSIS_PADS_NUM 2
+#define S5PCSIS_DEF_PIX_WIDTH 640
+#define S5PCSIS_DEF_PIX_HEIGHT 480
+
#endif
diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h
index c8e3b94bd91d..c7a5bc51d571 100644
--- a/drivers/media/video/s5p-fimc/regs-fimc.h
+++ b/drivers/media/video/s5p-fimc/regs-fimc.h
@@ -107,6 +107,11 @@
#define S5P_CIOCTRL_YCBCR_3PLANE (0 << 3)
#define S5P_CIOCTRL_YCBCR_2PLANE (1 << 3)
#define S5P_CIOCTRL_YCBCR_PLANE_MASK (1 << 3)
+#define S5P_CIOCTRL_ALPHA_OUT_MASK (0xff << 4)
+#define S5P_CIOCTRL_RGB16FMT_MASK (3 << 16)
+#define S5P_CIOCTRL_RGB565 (0 << 16)
+#define S5P_CIOCTRL_ARGB1555 (1 << 16)
+#define S5P_CIOCTRL_ARGB4444 (2 << 16)
#define S5P_CIOCTRL_ORDER2P_SHIFT (24)
#define S5P_CIOCTRL_ORDER2P_MASK (3 << 24)
#define S5P_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24)
diff --git a/drivers/media/video/s5p-g2d/Makefile b/drivers/media/video/s5p-g2d/Makefile
new file mode 100644
index 000000000000..2c48c416a804
--- /dev/null
+++ b/drivers/media/video/s5p-g2d/Makefile
@@ -0,0 +1,3 @@
+s5p-g2d-objs := g2d.o g2d-hw.o
+
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d.o
diff --git a/drivers/media/video/s5p-g2d/g2d-hw.c b/drivers/media/video/s5p-g2d/g2d-hw.c
new file mode 100644
index 000000000000..5b86cbe408e2
--- /dev/null
+++ b/drivers/media/video/s5p-g2d/g2d-hw.c
@@ -0,0 +1,109 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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
+ */
+
+#include <linux/io.h>
+
+#include "g2d.h"
+#include "g2d-regs.h"
+
+#define w(x, a) writel((x), d->regs + (a))
+#define r(a) readl(d->regs + (a))
+
+/* g2d_reset clears all g2d registers */
+void g2d_reset(struct g2d_dev *d)
+{
+ w(1, SOFT_RESET_REG);
+}
+
+void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f)
+{
+ u32 n;
+
+ w(f->stride & 0xFFFF, SRC_STRIDE_REG);
+
+ n = f->o_height & 0xFFF;
+ n <<= 16;
+ n |= f->o_width & 0xFFF;
+ w(n, SRC_LEFT_TOP_REG);
+
+ n = f->bottom & 0xFFF;
+ n <<= 16;
+ n |= f->right & 0xFFF;
+ w(n, SRC_RIGHT_BOTTOM_REG);
+
+ w(f->fmt->hw, SRC_COLOR_MODE_REG);
+}
+
+void g2d_set_src_addr(struct g2d_dev *d, dma_addr_t a)
+{
+ w(a, SRC_BASE_ADDR_REG);
+}
+
+void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f)
+{
+ u32 n;
+
+ w(f->stride & 0xFFFF, DST_STRIDE_REG);
+
+ n = f->o_height & 0xFFF;
+ n <<= 16;
+ n |= f->o_width & 0xFFF;
+ w(n, DST_LEFT_TOP_REG);
+
+ n = f->bottom & 0xFFF;
+ n <<= 16;
+ n |= f->right & 0xFFF;
+ w(n, DST_RIGHT_BOTTOM_REG);
+
+ w(f->fmt->hw, DST_COLOR_MODE_REG);
+}
+
+void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a)
+{
+ w(a, DST_BASE_ADDR_REG);
+}
+
+void g2d_set_rop4(struct g2d_dev *d, u32 r)
+{
+ w(r, ROP4_REG);
+}
+
+void g2d_set_flip(struct g2d_dev *d, u32 r)
+{
+ w(r, SRC_MSK_DIRECT_REG);
+}
+
+u32 g2d_cmd_stretch(u32 e)
+{
+ e &= 1;
+ return e << 4;
+}
+
+void g2d_set_cmd(struct g2d_dev *d, u32 c)
+{
+ w(c, BITBLT_COMMAND_REG);
+}
+
+void g2d_start(struct g2d_dev *d)
+{
+ /* Clear cache */
+ w(0x7, CACHECTL_REG);
+ /* Enable interrupt */
+ w(1, INTEN_REG);
+ /* Start G2D engine */
+ w(1, BITBLT_START_REG);
+}
+
+void g2d_clear_int(struct g2d_dev *d)
+{
+ w(1, INTC_PEND_REG);
+}
diff --git a/drivers/media/video/s5p-g2d/g2d-regs.h b/drivers/media/video/s5p-g2d/g2d-regs.h
new file mode 100644
index 000000000000..02e1cf50da4e
--- /dev/null
+++ b/drivers/media/video/s5p-g2d/g2d-regs.h
@@ -0,0 +1,115 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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
+ */
+
+/* General Registers */
+#define SOFT_RESET_REG 0x0000 /* Software reset reg */
+#define INTEN_REG 0x0004 /* Interrupt Enable reg */
+#define INTC_PEND_REG 0x000C /* Interrupt Control Pending reg */
+#define FIFO_STAT_REG 0x0010 /* Command FIFO Status reg */
+#define AXI_ID_MODE_REG 0x0014 /* AXI Read ID Mode reg */
+#define CACHECTL_REG 0x0018 /* Cache & Buffer clear reg */
+#define AXI_MODE_REG 0x001C /* AXI Mode reg */
+
+/* Command Registers */
+#define BITBLT_START_REG 0x0100 /* BitBLT Start reg */
+#define BITBLT_COMMAND_REG 0x0104 /* Command reg for BitBLT */
+
+/* Parameter Setting Registers (Rotate & Direction) */
+#define ROTATE_REG 0x0200 /* Rotation reg */
+#define SRC_MSK_DIRECT_REG 0x0204 /* Src and Mask Direction reg */
+#define DST_PAT_DIRECT_REG 0x0208 /* Dest and Pattern Direction reg */
+
+/* Parameter Setting Registers (Src) */
+#define SRC_SELECT_REG 0x0300 /* Src Image Selection reg */
+#define SRC_BASE_ADDR_REG 0x0304 /* Src Image Base Address reg */
+#define SRC_STRIDE_REG 0x0308 /* Src Stride reg */
+#define SRC_COLOR_MODE_REG 0x030C /* Src Image Color Mode reg */
+#define SRC_LEFT_TOP_REG 0x0310 /* Src Left Top Coordinate reg */
+#define SRC_RIGHT_BOTTOM_REG 0x0314 /* Src Right Bottom Coordinate reg */
+
+/* Parameter Setting Registers (Dest) */
+#define DST_SELECT_REG 0x0400 /* Dest Image Selection reg */
+#define DST_BASE_ADDR_REG 0x0404 /* Dest Image Base Address reg */
+#define DST_STRIDE_REG 0x0408 /* Dest Stride reg */
+#define DST_COLOR_MODE_REG 0x040C /* Dest Image Color Mode reg */
+#define DST_LEFT_TOP_REG 0x0410 /* Dest Left Top Coordinate reg */
+#define DST_RIGHT_BOTTOM_REG 0x0414 /* Dest Right Bottom Coordinate reg */
+
+/* Parameter Setting Registers (Pattern) */
+#define PAT_BASE_ADDR_REG 0x0500 /* Pattern Image Base Address reg */
+#define PAT_SIZE_REG 0x0504 /* Pattern Image Size reg */
+#define PAT_COLOR_MODE_REG 0x0508 /* Pattern Image Color Mode reg */
+#define PAT_OFFSET_REG 0x050C /* Pattern Left Top Coordinate reg */
+#define PAT_STRIDE_REG 0x0510 /* Pattern Stride reg */
+
+/* Parameter Setting Registers (Mask) */
+#define MASK_BASE_ADDR_REG 0x0520 /* Mask Base Address reg */
+#define MASK_STRIDE_REG 0x0524 /* Mask Stride reg */
+
+/* Parameter Setting Registers (Clipping Window) */
+#define CW_LT_REG 0x0600 /* LeftTop coordinates of Clip Window */
+#define CW_RB_REG 0x0604 /* RightBottom coordinates of Clip
+ Window */
+
+/* Parameter Setting Registers (ROP & Alpha Setting) */
+#define THIRD_OPERAND_REG 0x0610 /* Third Operand Selection reg */
+#define ROP4_REG 0x0614 /* Raster Operation reg */
+#define ALPHA_REG 0x0618 /* Alpha value, Fading offset value */
+
+/* Parameter Setting Registers (Color) */
+#define FG_COLOR_REG 0x0700 /* Foreground Color reg */
+#define BG_COLOR_REG 0x0704 /* Background Color reg */
+#define BS_COLOR_REG 0x0708 /* Blue Screen Color reg */
+
+/* Parameter Setting Registers (Color Key) */
+#define SRC_COLORKEY_CTRL_REG 0x0710 /* Src Colorkey control reg */
+#define SRC_COLORKEY_DR_MIN_REG 0x0714 /* Src Colorkey Decision Reference
+ Min reg */
+#define SRC_COLORKEY_DR_MAX_REG 0x0718 /* Src Colorkey Decision Reference
+ Max reg */
+#define DST_COLORKEY_CTRL_REG 0x071C /* Dest Colorkey control reg */
+#define DST_COLORKEY_DR_MIN_REG 0x0720 /* Dest Colorkey Decision Reference
+ Min reg */
+#define DST_COLORKEY_DR_MAX_REG 0x0724 /* Dest Colorkey Decision Reference
+ Max reg */
+
+/* Color mode values */
+
+#define ORDER_XRGB 0
+#define ORDER_RGBX 1
+#define ORDER_XBGR 2
+#define ORDER_BGRX 3
+
+#define MODE_XRGB_8888 0
+#define MODE_ARGB_8888 1
+#define MODE_RGB_565 2
+#define MODE_XRGB_1555 3
+#define MODE_ARGB_1555 4
+#define MODE_XRGB_4444 5
+#define MODE_ARGB_4444 6
+#define MODE_PACKED_RGB_888 7
+
+#define COLOR_MODE(o, m) (((o) << 4) | (m))
+
+/* ROP4 operation values */
+#define ROP4_COPY 0xCCCC
+#define ROP4_INVERT 0x3333
+
+/* Hardware limits */
+#define MAX_WIDTH 8000
+#define MAX_HEIGHT 8000
+
+#define G2D_TIMEOUT 500
+
+#define DEFAULT_WIDTH 100
+#define DEFAULT_HEIGHT 100
+
diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p-g2d/g2d.c
new file mode 100644
index 000000000000..789de74014e5
--- /dev/null
+++ b/drivers/media/video/s5p-g2d/g2d.c
@@ -0,0 +1,848 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "g2d.h"
+#include "g2d-regs.h"
+
+#define fh2ctx(__fh) container_of(__fh, struct g2d_ctx, fh)
+
+static struct g2d_fmt formats[] = {
+ {
+ .name = "XRGB_8888",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = 32,
+ .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_8888),
+ },
+ {
+ .name = "RGB_565",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .depth = 16,
+ .hw = COLOR_MODE(ORDER_XRGB, MODE_RGB_565),
+ },
+ {
+ .name = "XRGB_1555",
+ .fourcc = V4L2_PIX_FMT_RGB555X,
+ .depth = 16,
+ .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_1555),
+ },
+ {
+ .name = "XRGB_4444",
+ .fourcc = V4L2_PIX_FMT_RGB444,
+ .depth = 16,
+ .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_4444),
+ },
+ {
+ .name = "PACKED_RGB_888",
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .depth = 24,
+ .hw = COLOR_MODE(ORDER_XRGB, MODE_PACKED_RGB_888),
+ },
+};
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+struct g2d_frame def_frame = {
+ .width = DEFAULT_WIDTH,
+ .height = DEFAULT_HEIGHT,
+ .c_width = DEFAULT_WIDTH,
+ .c_height = DEFAULT_HEIGHT,
+ .o_width = 0,
+ .o_height = 0,
+ .fmt = &formats[0],
+ .right = DEFAULT_WIDTH,
+ .bottom = DEFAULT_HEIGHT,
+};
+
+struct g2d_fmt *find_fmt(struct v4l2_format *f)
+{
+ unsigned int i;
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].fourcc == f->fmt.pix.pixelformat)
+ return &formats[i];
+ }
+ return NULL;
+}
+
+
+static struct g2d_frame *get_frame(struct g2d_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ return &ctx->in;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return &ctx->out;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+}
+
+static int g2d_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct g2d_ctx *ctx = vb2_get_drv_priv(vq);
+ struct g2d_frame *f = get_frame(ctx, vq->type);
+
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ sizes[0] = f->size;
+ *nplanes = 1;
+ alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+ if (*nbuffers == 0)
+ *nbuffers = 1;
+
+ return 0;
+}
+
+static int g2d_buf_prepare(struct vb2_buffer *vb)
+{
+ struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct g2d_frame *f = get_frame(ctx, vb->vb2_queue->type);
+
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+ vb2_set_plane_payload(vb, 0, f->size);
+ return 0;
+}
+
+static void g2d_buf_queue(struct vb2_buffer *vb)
+{
+ struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+
+static struct vb2_ops g2d_qops = {
+ .queue_setup = g2d_queue_setup,
+ .buf_prepare = g2d_buf_prepare,
+ .buf_queue = g2d_buf_queue,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct g2d_ctx *ctx = priv;
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->drv_priv = ctx;
+ src_vq->ops = &g2d_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->drv_priv = ctx;
+ dst_vq->ops = &g2d_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+ return vb2_queue_init(dst_vq);
+}
+
+static int g2d_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx,
+ ctrl_handler);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->dev->ctrl_lock, flags);
+ switch (ctrl->id) {
+ case V4L2_CID_COLORFX:
+ if (ctrl->val == V4L2_COLORFX_NEGATIVE)
+ ctx->rop = ROP4_INVERT;
+ else
+ ctx->rop = ROP4_COPY;
+ break;
+
+ case V4L2_CID_HFLIP:
+ ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1);
+ break;
+
+ }
+ spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags);
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops g2d_ctrl_ops = {
+ .s_ctrl = g2d_s_ctrl,
+};
+
+int g2d_setup_ctrls(struct g2d_ctx *ctx)
+{
+ struct g2d_dev *dev = ctx->dev;
+
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+ ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+ ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std_menu(
+ &ctx->ctrl_handler,
+ &g2d_ctrl_ops,
+ V4L2_CID_COLORFX,
+ V4L2_COLORFX_NEGATIVE,
+ ~((1 << V4L2_COLORFX_NONE) | (1 << V4L2_COLORFX_NEGATIVE)),
+ V4L2_COLORFX_NONE);
+
+ if (ctx->ctrl_handler.error) {
+ int err = ctx->ctrl_handler.error;
+ v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n");
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ return err;
+ }
+
+ v4l2_ctrl_cluster(2, &ctx->ctrl_hflip);
+
+ return 0;
+}
+
+static int g2d_open(struct file *file)
+{
+ struct g2d_dev *dev = video_drvdata(file);
+ struct g2d_ctx *ctx = NULL;
+ int ret = 0;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ ctx->dev = dev;
+ /* Set default formats */
+ ctx->in = def_frame;
+ ctx->out = def_frame;
+
+ ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+ if (IS_ERR(ctx->m2m_ctx)) {
+ ret = PTR_ERR(ctx->m2m_ctx);
+ kfree(ctx);
+ return ret;
+ }
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ g2d_setup_ctrls(ctx);
+
+ /* Write the default values to the ctx struct */
+ v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+
+ ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+ v4l2_info(&dev->v4l2_dev, "instance opened\n");
+ return 0;
+}
+
+static int g2d_release(struct file *file)
+{
+ struct g2d_dev *dev = video_drvdata(file);
+ struct g2d_ctx *ctx = fh2ctx(file->private_data);
+
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ v4l2_info(&dev->v4l2_dev, "instance closed\n");
+ return 0;
+}
+
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1);
+ strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_STREAMING;
+ return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
+{
+ struct g2d_fmt *fmt;
+ if (f->index >= NUM_FORMATS)
+ return -EINVAL;
+ fmt = &formats[f->index];
+ f->pixelformat = fmt->fourcc;
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ return 0;
+}
+
+static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+ struct g2d_ctx *ctx = prv;
+ struct vb2_queue *vq;
+ struct g2d_frame *frm;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+ frm = get_frame(ctx, f->type);
+ if (IS_ERR(frm))
+ return PTR_ERR(frm);
+
+ f->fmt.pix.width = frm->width;
+ f->fmt.pix.height = frm->height;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.pixelformat = frm->fmt->fourcc;
+ f->fmt.pix.bytesperline = (frm->width * frm->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = frm->size;
+ return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+ struct g2d_fmt *fmt;
+ enum v4l2_field *field;
+
+ fmt = find_fmt(f);
+ if (!fmt)
+ return -EINVAL;
+
+ field = &f->fmt.pix.field;
+ if (*field == V4L2_FIELD_ANY)
+ *field = V4L2_FIELD_NONE;
+ else if (*field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ if (f->fmt.pix.width > MAX_WIDTH)
+ f->fmt.pix.width = MAX_WIDTH;
+ if (f->fmt.pix.height > MAX_HEIGHT)
+ f->fmt.pix.height = MAX_HEIGHT;
+
+ if (f->fmt.pix.width < 1)
+ f->fmt.pix.width = 1;
+ if (f->fmt.pix.height < 1)
+ f->fmt.pix.height = 1;
+
+ f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+ struct g2d_ctx *ctx = prv;
+ struct g2d_dev *dev = ctx->dev;
+ struct vb2_queue *vq;
+ struct g2d_frame *frm;
+ struct g2d_fmt *fmt;
+ int ret = 0;
+
+ /* Adjust all values accordingly to the hardware capabilities
+ * and chosen format. */
+ ret = vidioc_try_fmt(file, prv, f);
+ if (ret)
+ return ret;
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type);
+ return -EBUSY;
+ }
+ frm = get_frame(ctx, f->type);
+ if (IS_ERR(frm))
+ return PTR_ERR(frm);
+ fmt = find_fmt(f);
+ if (!fmt)
+ return -EINVAL;
+ frm->width = f->fmt.pix.width;
+ frm->height = f->fmt.pix.height;
+ frm->size = f->fmt.pix.sizeimage;
+ /* Reset crop settings */
+ frm->o_width = 0;
+ frm->o_height = 0;
+ frm->c_width = frm->width;
+ frm->c_height = frm->height;
+ frm->right = frm->width;
+ frm->bottom = frm->height;
+ frm->fmt = fmt;
+ frm->stride = f->fmt.pix.bytesperline;
+ return 0;
+}
+
+static unsigned int g2d_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct g2d_ctx *ctx = fh2ctx(file->private_data);
+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+static int g2d_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct g2d_ctx *ctx = fh2ctx(file->private_data);
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct g2d_ctx *ctx = priv;
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct g2d_ctx *ctx = priv;
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct g2d_ctx *ctx = priv;
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct g2d_ctx *ctx = priv;
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct g2d_ctx *ctx = priv;
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct g2d_ctx *ctx = priv;
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *cr)
+{
+ struct g2d_ctx *ctx = priv;
+ struct g2d_frame *f;
+
+ f = get_frame(ctx, cr->type);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = f->width;
+ cr->bounds.height = f->height;
+ cr->defrect = cr->bounds;
+ return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr)
+{
+ struct g2d_ctx *ctx = prv;
+ struct g2d_frame *f;
+
+ f = get_frame(ctx, cr->type);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ cr->c.left = f->o_height;
+ cr->c.top = f->o_width;
+ cr->c.width = f->c_width;
+ cr->c.height = f->c_height;
+ return 0;
+}
+
+static int vidioc_try_crop(struct file *file, void *prv, struct v4l2_crop *cr)
+{
+ struct g2d_ctx *ctx = prv;
+ struct g2d_dev *dev = ctx->dev;
+ struct g2d_frame *f;
+
+ f = get_frame(ctx, cr->type);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ if (cr->c.top < 0 || cr->c.left < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "doesn't support negative values for top & left\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vidioc_s_crop(struct file *file, void *prv, struct v4l2_crop *cr)
+{
+ struct g2d_ctx *ctx = prv;
+ struct g2d_frame *f;
+ int ret;
+
+ ret = vidioc_try_crop(file, prv, cr);
+ if (ret)
+ return ret;
+ f = get_frame(ctx, cr->type);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ f->c_width = cr->c.width;
+ f->c_height = cr->c.height;
+ f->o_width = cr->c.left;
+ f->o_height = cr->c.top;
+ f->bottom = f->o_height + f->c_height;
+ f->right = f->o_width + f->c_width;
+ return 0;
+}
+
+static void g2d_lock(void *prv)
+{
+ struct g2d_ctx *ctx = prv;
+ struct g2d_dev *dev = ctx->dev;
+ mutex_lock(&dev->mutex);
+}
+
+static void g2d_unlock(void *prv)
+{
+ struct g2d_ctx *ctx = prv;
+ struct g2d_dev *dev = ctx->dev;
+ mutex_unlock(&dev->mutex);
+}
+
+static void job_abort(void *prv)
+{
+ struct g2d_ctx *ctx = prv;
+ struct g2d_dev *dev = ctx->dev;
+ int ret;
+
+ if (dev->curr == 0) /* No job currently running */
+ return;
+
+ ret = wait_event_timeout(dev->irq_queue,
+ dev->curr == 0,
+ msecs_to_jiffies(G2D_TIMEOUT));
+}
+
+static void device_run(void *prv)
+{
+ struct g2d_ctx *ctx = prv;
+ struct g2d_dev *dev = ctx->dev;
+ struct vb2_buffer *src, *dst;
+ unsigned long flags;
+ u32 cmd = 0;
+
+ dev->curr = ctx;
+
+ src = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+ clk_enable(dev->gate);
+ g2d_reset(dev);
+
+ spin_lock_irqsave(&dev->ctrl_lock, flags);
+
+ g2d_set_src_size(dev, &ctx->in);
+ g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0));
+
+ g2d_set_dst_size(dev, &ctx->out);
+ g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0));
+
+ g2d_set_rop4(dev, ctx->rop);
+ g2d_set_flip(dev, ctx->flip);
+
+ if (ctx->in.c_width != ctx->out.c_width ||
+ ctx->in.c_height != ctx->out.c_height)
+ cmd |= g2d_cmd_stretch(1);
+ g2d_set_cmd(dev, cmd);
+ g2d_start(dev);
+
+ spin_unlock_irqrestore(&dev->ctrl_lock, flags);
+}
+
+static irqreturn_t g2d_isr(int irq, void *prv)
+{
+ struct g2d_dev *dev = prv;
+ struct g2d_ctx *ctx = dev->curr;
+ struct vb2_buffer *src, *dst;
+
+ g2d_clear_int(dev);
+ clk_disable(dev->gate);
+
+ BUG_ON(ctx == 0);
+
+ src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+ BUG_ON(src == 0);
+ BUG_ON(dst == 0);
+
+ v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
+ v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
+
+ dev->curr = 0;
+ wake_up(&dev->irq_queue);
+ return IRQ_HANDLED;
+}
+
+static const struct v4l2_file_operations g2d_fops = {
+ .owner = THIS_MODULE,
+ .open = g2d_open,
+ .release = g2d_release,
+ .poll = g2d_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = g2d_mmap,
+};
+
+static const struct v4l2_ioctl_ops g2d_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt,
+
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt,
+ .vidioc_g_fmt_vid_out = vidioc_g_fmt,
+ .vidioc_try_fmt_vid_out = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_out = vidioc_s_fmt,
+
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+
+ .vidioc_g_crop = vidioc_g_crop,
+ .vidioc_s_crop = vidioc_s_crop,
+ .vidioc_cropcap = vidioc_cropcap,
+};
+
+static struct video_device g2d_videodev = {
+ .name = G2D_NAME,
+ .fops = &g2d_fops,
+ .ioctl_ops = &g2d_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release,
+};
+
+static struct v4l2_m2m_ops g2d_m2m_ops = {
+ .device_run = device_run,
+ .job_abort = job_abort,
+ .lock = g2d_lock,
+ .unlock = g2d_unlock,
+};
+
+static int g2d_probe(struct platform_device *pdev)
+{
+ struct g2d_dev *dev;
+ struct video_device *vfd;
+ struct resource *res;
+ int ret = 0;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ spin_lock_init(&dev->ctrl_lock);
+ mutex_init(&dev->mutex);
+ atomic_set(&dev->num_inst, 0);
+ init_waitqueue_head(&dev->irq_queue);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to find registers\n");
+ ret = -ENOENT;
+ goto free_dev;
+ }
+
+ dev->res_regs = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+
+ if (!dev->res_regs) {
+ dev_err(&pdev->dev, "failed to obtain register region\n");
+ ret = -ENOENT;
+ goto free_dev;
+ }
+
+ dev->regs = ioremap(res->start, resource_size(res));
+ if (!dev->regs) {
+ dev_err(&pdev->dev, "failed to map registers\n");
+ ret = -ENOENT;
+ goto rel_res_regs;
+ }
+
+ dev->clk = clk_get(&pdev->dev, "sclk_fimg2d");
+ if (IS_ERR_OR_NULL(dev->clk)) {
+ dev_err(&pdev->dev, "failed to get g2d clock\n");
+ ret = -ENXIO;
+ goto unmap_regs;
+ }
+
+ ret = clk_prepare(dev->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to prepare g2d clock\n");
+ goto put_clk;
+ }
+
+ dev->gate = clk_get(&pdev->dev, "fimg2d");
+ if (IS_ERR_OR_NULL(dev->gate)) {
+ dev_err(&pdev->dev, "failed to get g2d clock gate\n");
+ ret = -ENXIO;
+ goto unprep_clk;
+ }
+
+ ret = clk_prepare(dev->gate);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to prepare g2d clock gate\n");
+ goto put_clk_gate;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to find IRQ\n");
+ ret = -ENXIO;
+ goto unprep_clk_gate;
+ }
+
+ dev->irq = res->start;
+
+ ret = request_irq(dev->irq, g2d_isr, 0, pdev->name, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to install IRQ\n");
+ goto put_clk_gate;
+ }
+
+ dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(dev->alloc_ctx)) {
+ ret = PTR_ERR(dev->alloc_ctx);
+ goto rel_irq;
+ }
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ goto alloc_ctx_cleanup;
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto unreg_v4l2_dev;
+ }
+ *vfd = g2d_videodev;
+ vfd->lock = &dev->mutex;
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ goto rel_vdev;
+ }
+ video_set_drvdata(vfd, dev);
+ snprintf(vfd->name, sizeof(vfd->name), "%s", g2d_videodev.name);
+ dev->vfd = vfd;
+ v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n",
+ vfd->num);
+ platform_set_drvdata(pdev, dev);
+ dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops);
+ if (IS_ERR(dev->m2m_dev)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+ ret = PTR_ERR(dev->m2m_dev);
+ goto unreg_video_dev;
+ }
+
+ def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
+
+ return 0;
+
+unreg_video_dev:
+ video_unregister_device(dev->vfd);
+rel_vdev:
+ video_device_release(vfd);
+unreg_v4l2_dev:
+ v4l2_device_unregister(&dev->v4l2_dev);
+alloc_ctx_cleanup:
+ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+rel_irq:
+ free_irq(dev->irq, dev);
+unprep_clk_gate:
+ clk_unprepare(dev->gate);
+put_clk_gate:
+ clk_put(dev->gate);
+unprep_clk:
+ clk_unprepare(dev->clk);
+put_clk:
+ clk_put(dev->clk);
+unmap_regs:
+ iounmap(dev->regs);
+rel_res_regs:
+ release_resource(dev->res_regs);
+free_dev:
+ kfree(dev);
+ return ret;
+}
+
+static int g2d_remove(struct platform_device *pdev)
+{
+ struct g2d_dev *dev = (struct g2d_dev *)platform_get_drvdata(pdev);
+
+ v4l2_info(&dev->v4l2_dev, "Removing " G2D_NAME);
+ v4l2_m2m_release(dev->m2m_dev);
+ video_unregister_device(dev->vfd);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+ free_irq(dev->irq, dev);
+ clk_unprepare(dev->gate);
+ clk_put(dev->gate);
+ clk_unprepare(dev->clk);
+ clk_put(dev->clk);
+ iounmap(dev->regs);
+ release_resource(dev->res_regs);
+ kfree(dev);
+ return 0;
+}
+
+static struct platform_driver g2d_pdrv = {
+ .probe = g2d_probe,
+ .remove = g2d_remove,
+ .driver = {
+ .name = G2D_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(g2d_pdrv);
+
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_DESCRIPTION("S5P G2D 2d graphics accelerator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-g2d/g2d.h b/drivers/media/video/s5p-g2d/g2d.h
new file mode 100644
index 000000000000..1b82065aeaef
--- /dev/null
+++ b/drivers/media/video/s5p-g2d/g2d.h
@@ -0,0 +1,87 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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
+ */
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define G2D_NAME "s5p-g2d"
+
+struct g2d_dev {
+ struct v4l2_device v4l2_dev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct video_device *vfd;
+ struct mutex mutex;
+ spinlock_t ctrl_lock;
+ atomic_t num_inst;
+ struct vb2_alloc_ctx *alloc_ctx;
+ struct resource *res_regs;
+ void __iomem *regs;
+ struct clk *clk;
+ struct clk *gate;
+ struct g2d_ctx *curr;
+ int irq;
+ wait_queue_head_t irq_queue;
+};
+
+struct g2d_frame {
+ /* Original dimensions */
+ u32 width;
+ u32 height;
+ /* Crop size */
+ u32 c_width;
+ u32 c_height;
+ /* Offset */
+ u32 o_width;
+ u32 o_height;
+ /* Image format */
+ struct g2d_fmt *fmt;
+ /* Variables that can calculated once and reused */
+ u32 stride;
+ u32 bottom;
+ u32 right;
+ u32 size;
+};
+
+struct g2d_ctx {
+ struct v4l2_fh fh;
+ struct g2d_dev *dev;
+ struct v4l2_m2m_ctx *m2m_ctx;
+ struct g2d_frame in;
+ struct g2d_frame out;
+ struct v4l2_ctrl *ctrl_hflip;
+ struct v4l2_ctrl *ctrl_vflip;
+ struct v4l2_ctrl_handler ctrl_handler;
+ u32 rop;
+ u32 flip;
+};
+
+struct g2d_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+ u32 hw;
+};
+
+
+void g2d_reset(struct g2d_dev *d);
+void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f);
+void g2d_set_src_addr(struct g2d_dev *d, dma_addr_t a);
+void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f);
+void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a);
+void g2d_start(struct g2d_dev *d);
+void g2d_clear_int(struct g2d_dev *d);
+void g2d_set_rop4(struct g2d_dev *d, u32 r);
+void g2d_set_flip(struct g2d_dev *d, u32 r);
+u32 g2d_cmd_stretch(u32 e);
+void g2d_set_cmd(struct g2d_dev *d, u32 c);
+
+
diff --git a/drivers/media/video/s5p-jpeg/Makefile b/drivers/media/video/s5p-jpeg/Makefile
new file mode 100644
index 000000000000..ddc2900d88a2
--- /dev/null
+++ b/drivers/media/video/s5p-jpeg/Makefile
@@ -0,0 +1,2 @@
+s5p-jpeg-objs := jpeg-core.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) := s5p-jpeg.o
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c
new file mode 100644
index 000000000000..5a49c307f9c1
--- /dev/null
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.c
@@ -0,0 +1,1563 @@
+/* linux/drivers/media/video/s5p-jpeg/jpeg-core.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gfp.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "jpeg-core.h"
+#include "jpeg-hw.h"
+
+static struct s5p_jpeg_fmt formats_enc[] = {
+ {
+ .name = "JPEG JFIF",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .colplanes = 1,
+ .types = MEM2MEM_CAPTURE,
+ },
+ {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .colplanes = 1,
+ .types = MEM2MEM_OUTPUT,
+ },
+ {
+ .name = "RGB565",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .depth = 16,
+ .colplanes = 1,
+ .types = MEM2MEM_OUTPUT,
+ },
+};
+#define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc)
+
+static struct s5p_jpeg_fmt formats_dec[] = {
+ {
+ .name = "YUV 4:2:0 planar, YCbCr",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = 12,
+ .colplanes = 3,
+ .h_align = 4,
+ .v_align = 4,
+ .types = MEM2MEM_CAPTURE,
+ },
+ {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .colplanes = 1,
+ .h_align = 4,
+ .v_align = 3,
+ .types = MEM2MEM_CAPTURE,
+ },
+ {
+ .name = "JPEG JFIF",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .colplanes = 1,
+ .types = MEM2MEM_OUTPUT,
+ },
+};
+#define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec)
+
+static const unsigned char qtbl_luminance[4][64] = {
+ {/* level 1 - high quality */
+ 8, 6, 6, 8, 12, 14, 16, 17,
+ 6, 6, 6, 8, 10, 13, 12, 15,
+ 6, 6, 7, 8, 13, 14, 18, 24,
+ 8, 8, 8, 14, 13, 19, 24, 35,
+ 12, 10, 13, 13, 20, 26, 34, 39,
+ 14, 13, 14, 19, 26, 34, 39, 39,
+ 16, 12, 18, 24, 34, 39, 39, 39,
+ 17, 15, 24, 35, 39, 39, 39, 39
+ },
+ {/* level 2 */
+ 12, 8, 8, 12, 17, 21, 24, 23,
+ 8, 9, 9, 11, 15, 19, 18, 23,
+ 8, 9, 10, 12, 19, 20, 27, 36,
+ 12, 11, 12, 21, 20, 28, 36, 53,
+ 17, 15, 19, 20, 30, 39, 51, 59,
+ 21, 19, 20, 28, 39, 51, 59, 59,
+ 24, 18, 27, 36, 51, 59, 59, 59,
+ 23, 23, 36, 53, 59, 59, 59, 59
+ },
+ {/* level 3 */
+ 16, 11, 11, 16, 23, 27, 31, 30,
+ 11, 12, 12, 15, 20, 23, 23, 30,
+ 11, 12, 13, 16, 23, 26, 35, 47,
+ 16, 15, 16, 23, 26, 37, 47, 64,
+ 23, 20, 23, 26, 39, 51, 64, 64,
+ 27, 23, 26, 37, 51, 64, 64, 64,
+ 31, 23, 35, 47, 64, 64, 64, 64,
+ 30, 30, 47, 64, 64, 64, 64, 64
+ },
+ {/*level 4 - low quality */
+ 20, 16, 25, 39, 50, 46, 62, 68,
+ 16, 18, 23, 38, 38, 53, 65, 68,
+ 25, 23, 31, 38, 53, 65, 68, 68,
+ 39, 38, 38, 53, 65, 68, 68, 68,
+ 50, 38, 53, 65, 68, 68, 68, 68,
+ 46, 53, 65, 68, 68, 68, 68, 68,
+ 62, 65, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68
+ }
+};
+
+static const unsigned char qtbl_chrominance[4][64] = {
+ {/* level 1 - high quality */
+ 9, 8, 9, 11, 14, 17, 19, 24,
+ 8, 10, 9, 11, 14, 13, 17, 22,
+ 9, 9, 13, 14, 13, 15, 23, 26,
+ 11, 11, 14, 14, 15, 20, 26, 33,
+ 14, 14, 13, 15, 20, 24, 33, 39,
+ 17, 13, 15, 20, 24, 32, 39, 39,
+ 19, 17, 23, 26, 33, 39, 39, 39,
+ 24, 22, 26, 33, 39, 39, 39, 39
+ },
+ {/* level 2 */
+ 13, 11, 13, 16, 20, 20, 29, 37,
+ 11, 14, 14, 14, 16, 20, 26, 32,
+ 13, 14, 15, 17, 20, 23, 35, 40,
+ 16, 14, 17, 21, 23, 30, 40, 50,
+ 20, 16, 20, 23, 30, 37, 50, 59,
+ 20, 20, 23, 30, 37, 48, 59, 59,
+ 29, 26, 35, 40, 50, 59, 59, 59,
+ 37, 32, 40, 50, 59, 59, 59, 59
+ },
+ {/* level 3 */
+ 17, 15, 17, 21, 20, 26, 38, 48,
+ 15, 19, 18, 17, 20, 26, 35, 43,
+ 17, 18, 20, 22, 26, 30, 46, 53,
+ 21, 17, 22, 28, 30, 39, 53, 64,
+ 20, 20, 26, 30, 39, 48, 64, 64,
+ 26, 26, 30, 39, 48, 63, 64, 64,
+ 38, 35, 46, 53, 64, 64, 64, 64,
+ 48, 43, 53, 64, 64, 64, 64, 64
+ },
+ {/*level 4 - low quality */
+ 21, 25, 32, 38, 54, 68, 68, 68,
+ 25, 28, 24, 38, 54, 68, 68, 68,
+ 32, 24, 32, 43, 66, 68, 68, 68,
+ 38, 38, 43, 53, 68, 68, 68, 68,
+ 54, 54, 66, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68
+ }
+};
+
+static const unsigned char hdctbl0[16] = {
+ 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char hdctblg0[12] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
+};
+static const unsigned char hactbl0[16] = {
+ 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+};
+static const unsigned char hactblg0[162] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
+{
+ return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
+}
+
+static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
+{
+ return container_of(fh, struct s5p_jpeg_ctx, fh);
+}
+
+static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
+ unsigned long tab, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
+}
+
+static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality)
+{
+ /* this driver fills quantisation table 0 with data for luma */
+ jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0),
+ ARRAY_SIZE(qtbl_luminance[quality]));
+}
+
+static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality)
+{
+ /* this driver fills quantisation table 1 with data for chroma */
+ jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1),
+ ARRAY_SIZE(qtbl_chrominance[quality]));
+}
+
+static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl,
+ unsigned long tab, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
+}
+
+static inline void jpeg_set_hdctbl(void __iomem *regs)
+{
+ /* this driver fills table 0 for this component */
+ jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0));
+}
+
+static inline void jpeg_set_hdctblg(void __iomem *regs)
+{
+ /* this driver fills table 0 for this component */
+ jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0));
+}
+
+static inline void jpeg_set_hactbl(void __iomem *regs)
+{
+ /* this driver fills table 0 for this component */
+ jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0));
+}
+
+static inline void jpeg_set_hactblg(void __iomem *regs)
+{
+ /* this driver fills table 0 for this component */
+ jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0));
+}
+
+/*
+ * ============================================================================
+ * Device file operations
+ * ============================================================================
+ */
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq);
+static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
+ __u32 pixelformat);
+static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
+
+static int s5p_jpeg_open(struct file *file)
+{
+ struct s5p_jpeg *jpeg = video_drvdata(file);
+ struct video_device *vfd = video_devdata(file);
+ struct s5p_jpeg_ctx *ctx;
+ struct s5p_jpeg_fmt *out_fmt;
+ int ret = 0;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ v4l2_fh_init(&ctx->fh, vfd);
+ /* Use separate control handler per file handle */
+ ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ ctx->jpeg = jpeg;
+ if (vfd == jpeg->vfd_encoder) {
+ ctx->mode = S5P_JPEG_ENCODE;
+ out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_RGB565);
+ } else {
+ ctx->mode = S5P_JPEG_DECODE;
+ out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
+ }
+
+ ret = s5p_jpeg_controls_create(ctx);
+ if (ret < 0)
+ goto error;
+
+ ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
+ if (IS_ERR(ctx->m2m_ctx)) {
+ ret = PTR_ERR(ctx->m2m_ctx);
+ goto error;
+ }
+
+ ctx->out_q.fmt = out_fmt;
+ ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
+ return 0;
+
+error:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ return ret;
+}
+
+static int s5p_jpeg_release(struct file *file)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+
+ return 0;
+}
+
+static unsigned int s5p_jpeg_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+
+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations s5p_jpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = s5p_jpeg_open,
+ .release = s5p_jpeg_release,
+ .poll = s5p_jpeg_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = s5p_jpeg_mmap,
+};
+
+/*
+ * ============================================================================
+ * video ioctl operations
+ * ============================================================================
+ */
+
+static int get_byte(struct s5p_jpeg_buffer *buf)
+{
+ if (buf->curr >= buf->size)
+ return -1;
+
+ return ((unsigned char *)buf->data)[buf->curr++];
+}
+
+static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
+{
+ unsigned int temp;
+ int byte;
+
+ byte = get_byte(buf);
+ if (byte == -1)
+ return -1;
+ temp = byte << 8;
+ byte = get_byte(buf);
+ if (byte == -1)
+ return -1;
+ *word = (unsigned int)byte | temp;
+ return 0;
+}
+
+static void skip(struct s5p_jpeg_buffer *buf, long len)
+{
+ if (len <= 0)
+ return;
+
+ while (len--)
+ get_byte(buf);
+}
+
+static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
+ unsigned long buffer, unsigned long size)
+{
+ int c, components, notfound;
+ unsigned int height, width, word;
+ long length;
+ struct s5p_jpeg_buffer jpeg_buffer;
+
+ jpeg_buffer.size = size;
+ jpeg_buffer.data = buffer;
+ jpeg_buffer.curr = 0;
+
+ notfound = 1;
+ while (notfound) {
+ c = get_byte(&jpeg_buffer);
+ if (c == -1)
+ break;
+ if (c != 0xff)
+ continue;
+ do
+ c = get_byte(&jpeg_buffer);
+ while (c == 0xff);
+ if (c == -1)
+ break;
+ if (c == 0)
+ continue;
+ length = 0;
+ switch (c) {
+ /* SOF0: baseline JPEG */
+ case SOF0:
+ if (get_word_be(&jpeg_buffer, &word))
+ break;
+ if (get_byte(&jpeg_buffer) == -1)
+ break;
+ if (get_word_be(&jpeg_buffer, &height))
+ break;
+ if (get_word_be(&jpeg_buffer, &width))
+ break;
+ components = get_byte(&jpeg_buffer);
+ if (components == -1)
+ break;
+ notfound = 0;
+
+ skip(&jpeg_buffer, components * 3);
+ break;
+
+ /* skip payload-less markers */
+ case RST ... RST + 7:
+ case SOI:
+ case EOI:
+ case TEM:
+ break;
+
+ /* skip uninteresting payload markers */
+ default:
+ if (get_word_be(&jpeg_buffer, &word))
+ break;
+ length = (long)word - 2;
+ skip(&jpeg_buffer, length);
+ break;
+ }
+ }
+ result->w = width;
+ result->h = height;
+ result->size = components;
+ return !notfound;
+}
+
+static int s5p_jpeg_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+ if (ctx->mode == S5P_JPEG_ENCODE) {
+ strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
+ sizeof(cap->driver));
+ strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
+ sizeof(cap->card));
+ } else {
+ strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
+ sizeof(cap->driver));
+ strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
+ sizeof(cap->card));
+ }
+ cap->bus_info[0] = 0;
+ cap->capabilities = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VIDEO_OUTPUT;
+ return 0;
+}
+
+static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
+ struct v4l2_fmtdesc *f, u32 type)
+{
+ int i, num = 0;
+
+ for (i = 0; i < n; ++i) {
+ if (formats[i].types & type) {
+ /* index-th format of type type found ? */
+ if (num == f->index)
+ break;
+ /* Correct type but haven't reached our index yet,
+ * just increment per-type index */
+ ++num;
+ }
+ }
+
+ /* Format not found */
+ if (i >= n)
+ return -EINVAL;
+
+ strlcpy(f->description, formats[i].name, sizeof(f->description));
+ f->pixelformat = formats[i].fourcc;
+
+ return 0;
+}
+
+static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+ if (ctx->mode == S5P_JPEG_ENCODE)
+ return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
+ MEM2MEM_CAPTURE);
+
+ return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_CAPTURE);
+}
+
+static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+ if (ctx->mode == S5P_JPEG_ENCODE)
+ return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
+ MEM2MEM_OUTPUT);
+
+ return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_OUTPUT);
+}
+
+static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return &ctx->out_q;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return &ctx->cap_q;
+
+ return NULL;
+}
+
+static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct s5p_jpeg_q_data *q_data = NULL;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
+
+ vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
+ return -EINVAL;
+ q_data = get_q_data(ct, f->type);
+ BUG_ON(q_data == NULL);
+
+ pix->width = q_data->w;
+ pix->height = q_data->h;
+ pix->field = V4L2_FIELD_NONE;
+ pix->pixelformat = q_data->fmt->fourcc;
+ pix->bytesperline = 0;
+ if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
+ u32 bpl = q_data->w;
+ if (q_data->fmt->colplanes == 1)
+ bpl = (bpl * q_data->fmt->depth) >> 3;
+ pix->bytesperline = bpl;
+ }
+ pix->sizeimage = q_data->size;
+
+ return 0;
+}
+
+static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
+ u32 pixelformat)
+{
+ unsigned int k;
+ struct s5p_jpeg_fmt *formats;
+ int n;
+
+ if (mode == S5P_JPEG_ENCODE) {
+ formats = formats_enc;
+ n = NUM_FORMATS_ENC;
+ } else {
+ formats = formats_dec;
+ n = NUM_FORMATS_DEC;
+ }
+
+ for (k = 0; k < n; k++) {
+ struct s5p_jpeg_fmt *fmt = &formats[k];
+ if (fmt->fourcc == pixelformat)
+ return fmt;
+ }
+
+ return NULL;
+
+}
+
+static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
+ unsigned int walign,
+ u32 *h, unsigned int hmin, unsigned int hmax,
+ unsigned int halign)
+{
+ int width, height, w_step, h_step;
+
+ width = *w;
+ height = *h;
+
+ w_step = 1 << walign;
+ h_step = 1 << halign;
+ v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
+
+ if (*w < width && (*w + w_step) < wmax)
+ *w += w_step;
+ if (*h < height && (*h + h_step) < hmax)
+ *h += h_step;
+
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
+ struct s5p_jpeg_ctx *ctx, int q_type)
+{
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = V4L2_FIELD_NONE;
+ else if (pix->field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ /* V4L2 specification suggests the driver corrects the format struct
+ * if any of the dimensions is unsupported */
+ if (q_type == MEM2MEM_OUTPUT)
+ jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
+ S5P_JPEG_MAX_WIDTH, 0,
+ &pix->height, S5P_JPEG_MIN_HEIGHT,
+ S5P_JPEG_MAX_HEIGHT, 0);
+ else
+ jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
+ S5P_JPEG_MAX_WIDTH, fmt->h_align,
+ &pix->height, S5P_JPEG_MIN_HEIGHT,
+ S5P_JPEG_MAX_HEIGHT, fmt->v_align);
+
+ if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
+ if (pix->sizeimage <= 0)
+ pix->sizeimage = PAGE_SIZE;
+ pix->bytesperline = 0;
+ } else {
+ u32 bpl = pix->bytesperline;
+
+ if (fmt->colplanes > 1 && bpl < pix->width)
+ bpl = pix->width; /* planar */
+
+ if (fmt->colplanes == 1 && /* packed */
+ (bpl << 3) * fmt->depth < pix->width)
+ bpl = (pix->width * fmt->depth) >> 3;
+
+ pix->bytesperline = bpl;
+ pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
+ }
+
+ return 0;
+}
+
+static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+ struct s5p_jpeg_fmt *fmt;
+
+ fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
+ if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+ v4l2_err(&ctx->jpeg->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE);
+}
+
+static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+ struct s5p_jpeg_fmt *fmt;
+
+ fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
+ if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+ v4l2_err(&ctx->jpeg->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT);
+}
+
+static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct s5p_jpeg_q_data *q_data = NULL;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = get_q_data(ct, f->type);
+ BUG_ON(q_data == NULL);
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ q_data->fmt = s5p_jpeg_find_format(ct->mode, pix->pixelformat);
+ q_data->w = pix->width;
+ q_data->h = pix->height;
+ if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
+ q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
+ else
+ q_data->size = pix->sizeimage;
+
+ return 0;
+}
+
+static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+
+ ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
+}
+
+static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+
+ ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
+}
+
+static int s5p_jpeg_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int s5p_jpeg_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int s5p_jpeg_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int s5p_jpeg_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int s5p_jpeg_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+int s5p_jpeg_g_selection(struct file *file, void *priv,
+ struct v4l2_selection *s)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* For JPEG blob active == default == bounds */
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_ACTIVE:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ s->r.width = ctx->out_q.w;
+ s->r.height = ctx->out_q.h;
+ break;
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ case V4L2_SEL_TGT_COMPOSE_PADDED:
+ s->r.width = ctx->cap_q.w;
+ s->r.height = ctx->cap_q.h;
+ break;
+ default:
+ return -EINVAL;
+ }
+ s->r.left = 0;
+ s->r.top = 0;
+ return 0;
+}
+
+/*
+ * V4L2 controls
+ */
+
+static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+ struct s5p_jpeg *jpeg = ctx->jpeg;
+ unsigned long flags;
+
+ switch (ctrl->id) {
+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+ spin_lock_irqsave(&jpeg->slock, flags);
+
+ WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
+ if (ctx->subsampling > 2)
+ ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
+ else
+ ctrl->val = ctx->subsampling;
+ spin_unlock_irqrestore(&jpeg->slock, flags);
+ break;
+ }
+
+ return 0;
+}
+
+static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->jpeg->slock, flags);
+
+ switch (ctrl->id) {
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val;
+ break;
+ case V4L2_CID_JPEG_RESTART_INTERVAL:
+ ctx->restart_interval = ctrl->val;
+ break;
+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+ ctx->subsampling = ctrl->val;
+ break;
+ }
+
+ spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
+ .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
+ .s_ctrl = s5p_jpeg_s_ctrl,
+};
+
+static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
+{
+ unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
+ struct v4l2_ctrl *ctrl;
+
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+ if (ctx->mode == S5P_JPEG_ENCODE) {
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ 0, 3, 1, 3);
+
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+ V4L2_CID_JPEG_RESTART_INTERVAL,
+ 0, 3, 0xffff, 0);
+ mask = ~0x06; /* 422, 420 */
+ }
+
+ ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+ V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
+ V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
+ V4L2_JPEG_CHROMA_SUBSAMPLING_422);
+
+ if (ctx->ctrl_handler.error)
+ return ctx->ctrl_handler.error;
+
+ if (ctx->mode == S5P_JPEG_DECODE)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+ V4L2_CTRL_FLAG_READ_ONLY;
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
+ .vidioc_querycap = s5p_jpeg_querycap,
+
+ .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
+
+ .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
+ .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
+
+ .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
+ .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
+
+ .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
+ .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
+
+ .vidioc_reqbufs = s5p_jpeg_reqbufs,
+ .vidioc_querybuf = s5p_jpeg_querybuf,
+
+ .vidioc_qbuf = s5p_jpeg_qbuf,
+ .vidioc_dqbuf = s5p_jpeg_dqbuf,
+
+ .vidioc_streamon = s5p_jpeg_streamon,
+ .vidioc_streamoff = s5p_jpeg_streamoff,
+
+ .vidioc_g_selection = s5p_jpeg_g_selection,
+};
+
+/*
+ * ============================================================================
+ * mem2mem callbacks
+ * ============================================================================
+ */
+
+static void s5p_jpeg_device_run(void *priv)
+{
+ struct s5p_jpeg_ctx *ctx = priv;
+ struct s5p_jpeg *jpeg = ctx->jpeg;
+ struct vb2_buffer *src_buf, *dst_buf;
+ unsigned long src_addr, dst_addr;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+
+ jpeg_reset(jpeg->regs);
+ jpeg_poweron(jpeg->regs);
+ jpeg_proc_mode(jpeg->regs, ctx->mode);
+ if (ctx->mode == S5P_JPEG_ENCODE) {
+ if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
+ jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565);
+ else
+ jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422);
+ jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
+ jpeg_dri(jpeg->regs, ctx->restart_interval);
+ jpeg_x(jpeg->regs, ctx->out_q.w);
+ jpeg_y(jpeg->regs, ctx->out_q.h);
+ jpeg_imgadr(jpeg->regs, src_addr);
+ jpeg_jpgadr(jpeg->regs, dst_addr);
+
+ /* ultimately comes from sizeimage from userspace */
+ jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
+
+ /* JPEG RGB to YCbCr conversion matrix */
+ jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
+ jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
+ jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
+ jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
+ jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
+ jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
+ jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
+ jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
+ jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
+
+ /*
+ * JPEG IP allows storing 4 quantization tables
+ * We fill table 0 for luma and table 1 for chroma
+ */
+ jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
+ jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
+ /* use table 0 for Y */
+ jpeg_qtbl(jpeg->regs, 1, 0);
+ /* use table 1 for Cb and Cr*/
+ jpeg_qtbl(jpeg->regs, 2, 1);
+ jpeg_qtbl(jpeg->regs, 3, 1);
+
+ /* Y, Cb, Cr use Huffman table 0 */
+ jpeg_htbl_ac(jpeg->regs, 1);
+ jpeg_htbl_dc(jpeg->regs, 1);
+ jpeg_htbl_ac(jpeg->regs, 2);
+ jpeg_htbl_dc(jpeg->regs, 2);
+ jpeg_htbl_ac(jpeg->regs, 3);
+ jpeg_htbl_dc(jpeg->regs, 3);
+ } else { /* S5P_JPEG_DECODE */
+ jpeg_rst_int_enable(jpeg->regs, true);
+ jpeg_data_num_int_enable(jpeg->regs, true);
+ jpeg_final_mcu_num_int_enable(jpeg->regs, true);
+ if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
+ jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
+ else
+ jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
+ jpeg_jpgadr(jpeg->regs, src_addr);
+ jpeg_imgadr(jpeg->regs, dst_addr);
+ }
+
+ jpeg_start(jpeg->regs);
+}
+
+static int s5p_jpeg_job_ready(void *priv)
+{
+ struct s5p_jpeg_ctx *ctx = priv;
+
+ if (ctx->mode == S5P_JPEG_DECODE)
+ return ctx->hdr_parsed;
+ return 1;
+}
+
+static void s5p_jpeg_job_abort(void *priv)
+{
+}
+
+static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
+ .device_run = s5p_jpeg_device_run,
+ .job_ready = s5p_jpeg_job_ready,
+ .job_abort = s5p_jpeg_job_abort,
+};
+
+/*
+ * ============================================================================
+ * Queue operations
+ * ============================================================================
+ */
+
+static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+ struct s5p_jpeg_q_data *q_data = NULL;
+ unsigned int size, count = *nbuffers;
+
+ q_data = get_q_data(ctx, vq->type);
+ BUG_ON(q_data == NULL);
+
+ size = q_data->size;
+
+ /*
+ * header is parsed during decoding and parsed information stored
+ * in the context so we do not allow another buffer to overwrite it
+ */
+ if (ctx->mode == S5P_JPEG_DECODE)
+ count = 1;
+
+ *nbuffers = count;
+ *nplanes = 1;
+ sizes[0] = size;
+ alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
+
+ return 0;
+}
+
+static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
+{
+ struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct s5p_jpeg_q_data *q_data = NULL;
+
+ q_data = get_q_data(ctx, vb->vb2_queue->type);
+ BUG_ON(q_data == NULL);
+
+ if (vb2_plane_size(vb, 0) < q_data->size) {
+ pr_err("%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0),
+ (long)q_data->size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, q_data->size);
+
+ return 0;
+}
+
+static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
+{
+ struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ if (ctx->mode == S5P_JPEG_DECODE &&
+ vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ struct s5p_jpeg_q_data tmp, *q_data;
+ ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
+ (unsigned long)vb2_plane_vaddr(vb, 0),
+ min((unsigned long)ctx->out_q.size,
+ vb2_get_plane_payload(vb, 0)));
+ if (!ctx->hdr_parsed) {
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ return;
+ }
+
+ q_data = &ctx->out_q;
+ q_data->w = tmp.w;
+ q_data->h = tmp.h;
+
+ q_data = &ctx->cap_q;
+ q_data->w = tmp.w;
+ q_data->h = tmp.h;
+
+ jpeg_bound_align_image(&q_data->w, S5P_JPEG_MIN_WIDTH,
+ S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align,
+ &q_data->h, S5P_JPEG_MIN_HEIGHT,
+ S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align
+ );
+ q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
+ }
+ if (ctx->m2m_ctx)
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void s5p_jpeg_wait_prepare(struct vb2_queue *vq)
+{
+ struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+
+ mutex_unlock(&ctx->jpeg->lock);
+}
+
+static void s5p_jpeg_wait_finish(struct vb2_queue *vq)
+{
+ struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+
+ mutex_lock(&ctx->jpeg->lock);
+}
+
+static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+ int ret;
+
+ ret = pm_runtime_get_sync(ctx->jpeg->dev);
+
+ return ret > 0 ? 0 : ret;
+}
+
+static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
+{
+ struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+
+ pm_runtime_put(ctx->jpeg->dev);
+
+ return 0;
+}
+
+static struct vb2_ops s5p_jpeg_qops = {
+ .queue_setup = s5p_jpeg_queue_setup,
+ .buf_prepare = s5p_jpeg_buf_prepare,
+ .buf_queue = s5p_jpeg_buf_queue,
+ .wait_prepare = s5p_jpeg_wait_prepare,
+ .wait_finish = s5p_jpeg_wait_finish,
+ .start_streaming = s5p_jpeg_start_streaming,
+ .stop_streaming = s5p_jpeg_stop_streaming,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct s5p_jpeg_ctx *ctx = priv;
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &s5p_jpeg_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &s5p_jpeg_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+ return vb2_queue_init(dst_vq);
+}
+
+/*
+ * ============================================================================
+ * ISR
+ * ============================================================================
+ */
+
+static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
+{
+ struct s5p_jpeg *jpeg = dev_id;
+ struct s5p_jpeg_ctx *curr_ctx;
+ struct vb2_buffer *src_buf, *dst_buf;
+ unsigned long payload_size = 0;
+ enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
+ bool enc_jpeg_too_large = false;
+ bool timer_elapsed = false;
+ bool op_completed = false;
+
+ spin_lock(&jpeg->slock);
+
+ curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+
+ src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+ if (curr_ctx->mode == S5P_JPEG_ENCODE)
+ enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs);
+ timer_elapsed = jpeg_timer_stat(jpeg->regs);
+ op_completed = jpeg_result_stat_ok(jpeg->regs);
+ if (curr_ctx->mode == S5P_JPEG_DECODE)
+ op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs);
+
+ if (enc_jpeg_too_large) {
+ state = VB2_BUF_STATE_ERROR;
+ jpeg_clear_enc_stream_stat(jpeg->regs);
+ } else if (timer_elapsed) {
+ state = VB2_BUF_STATE_ERROR;
+ jpeg_clear_timer_stat(jpeg->regs);
+ } else if (!op_completed) {
+ state = VB2_BUF_STATE_ERROR;
+ } else {
+ payload_size = jpeg_compressed_size(jpeg->regs);
+ }
+
+ v4l2_m2m_buf_done(src_buf, state);
+ if (curr_ctx->mode == S5P_JPEG_ENCODE)
+ vb2_set_plane_payload(dst_buf, 0, payload_size);
+ v4l2_m2m_buf_done(dst_buf, state);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx);
+
+ curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs);
+ spin_unlock(&jpeg->slock);
+
+ jpeg_clear_int(jpeg->regs);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * ============================================================================
+ * Driver basic infrastructure
+ * ============================================================================
+ */
+
+static int s5p_jpeg_probe(struct platform_device *pdev)
+{
+ struct s5p_jpeg *jpeg;
+ struct resource *res;
+ int ret;
+
+ /* JPEG IP abstraction struct */
+ jpeg = kzalloc(sizeof(struct s5p_jpeg), GFP_KERNEL);
+ if (!jpeg)
+ return -ENOMEM;
+
+ mutex_init(&jpeg->lock);
+ spin_lock_init(&jpeg->slock);
+ jpeg->dev = &pdev->dev;
+
+ /* memory-mapped registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "cannot find IO resource\n");
+ ret = -ENOENT;
+ goto jpeg_alloc_rollback;
+ }
+
+ jpeg->ioarea = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+ if (!jpeg->ioarea) {
+ dev_err(&pdev->dev, "cannot request IO\n");
+ ret = -ENXIO;
+ goto jpeg_alloc_rollback;
+ }
+
+ jpeg->regs = ioremap(res->start, resource_size(res));
+ if (!jpeg->regs) {
+ dev_err(&pdev->dev, "cannot map IO\n");
+ ret = -ENXIO;
+ goto mem_region_rollback;
+ }
+
+ dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
+ jpeg->regs, jpeg->ioarea, res);
+
+ /* interrupt service routine registration */
+ jpeg->irq = ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "cannot find IRQ\n");
+ goto ioremap_rollback;
+ }
+
+ ret = request_irq(jpeg->irq, s5p_jpeg_irq, 0,
+ dev_name(&pdev->dev), jpeg);
+
+ if (ret) {
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
+ goto ioremap_rollback;
+ }
+
+ /* clocks */
+ jpeg->clk = clk_get(&pdev->dev, "jpeg");
+ if (IS_ERR(jpeg->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ ret = PTR_ERR(jpeg->clk);
+ goto request_irq_rollback;
+ }
+ dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
+ clk_enable(jpeg->clk);
+
+ /* v4l2 device */
+ ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+ goto clk_get_rollback;
+ }
+
+ /* mem2mem device */
+ jpeg->m2m_dev = v4l2_m2m_init(&s5p_jpeg_m2m_ops);
+ if (IS_ERR(jpeg->m2m_dev)) {
+ v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
+ ret = PTR_ERR(jpeg->m2m_dev);
+ goto device_register_rollback;
+ }
+
+ jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(jpeg->alloc_ctx)) {
+ v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
+ ret = PTR_ERR(jpeg->alloc_ctx);
+ goto m2m_init_rollback;
+ }
+
+ /* JPEG encoder /dev/videoX node */
+ jpeg->vfd_encoder = video_device_alloc();
+ if (!jpeg->vfd_encoder) {
+ v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto vb2_allocator_rollback;
+ }
+ strlcpy(jpeg->vfd_encoder->name, S5P_JPEG_M2M_NAME,
+ sizeof(jpeg->vfd_encoder->name));
+ jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
+ jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
+ jpeg->vfd_encoder->minor = -1;
+ jpeg->vfd_encoder->release = video_device_release;
+ jpeg->vfd_encoder->lock = &jpeg->lock;
+ jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
+
+ ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
+ goto enc_vdev_alloc_rollback;
+ }
+
+ video_set_drvdata(jpeg->vfd_encoder, jpeg);
+ v4l2_info(&jpeg->v4l2_dev,
+ "encoder device registered as /dev/video%d\n",
+ jpeg->vfd_encoder->num);
+
+ /* JPEG decoder /dev/videoX node */
+ jpeg->vfd_decoder = video_device_alloc();
+ if (!jpeg->vfd_decoder) {
+ v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto enc_vdev_register_rollback;
+ }
+ strlcpy(jpeg->vfd_decoder->name, S5P_JPEG_M2M_NAME,
+ sizeof(jpeg->vfd_decoder->name));
+ jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
+ jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
+ jpeg->vfd_decoder->minor = -1;
+ jpeg->vfd_decoder->release = video_device_release;
+ jpeg->vfd_decoder->lock = &jpeg->lock;
+ jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
+
+ ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
+ goto dec_vdev_alloc_rollback;
+ }
+
+ video_set_drvdata(jpeg->vfd_decoder, jpeg);
+ v4l2_info(&jpeg->v4l2_dev,
+ "decoder device registered as /dev/video%d\n",
+ jpeg->vfd_decoder->num);
+
+ /* final statements & power management */
+ platform_set_drvdata(pdev, jpeg);
+
+ pm_runtime_enable(&pdev->dev);
+
+ v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
+
+ return 0;
+
+dec_vdev_alloc_rollback:
+ video_device_release(jpeg->vfd_decoder);
+
+enc_vdev_register_rollback:
+ video_unregister_device(jpeg->vfd_encoder);
+
+enc_vdev_alloc_rollback:
+ video_device_release(jpeg->vfd_encoder);
+
+vb2_allocator_rollback:
+ vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
+
+m2m_init_rollback:
+ v4l2_m2m_release(jpeg->m2m_dev);
+
+device_register_rollback:
+ v4l2_device_unregister(&jpeg->v4l2_dev);
+
+clk_get_rollback:
+ clk_disable(jpeg->clk);
+ clk_put(jpeg->clk);
+
+request_irq_rollback:
+ free_irq(jpeg->irq, jpeg);
+
+ioremap_rollback:
+ iounmap(jpeg->regs);
+
+mem_region_rollback:
+ release_resource(jpeg->ioarea);
+ release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea));
+
+jpeg_alloc_rollback:
+ kfree(jpeg);
+ return ret;
+}
+
+static int s5p_jpeg_remove(struct platform_device *pdev)
+{
+ struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(jpeg->dev);
+
+ video_unregister_device(jpeg->vfd_decoder);
+ video_device_release(jpeg->vfd_decoder);
+ video_unregister_device(jpeg->vfd_encoder);
+ video_device_release(jpeg->vfd_encoder);
+ vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
+ v4l2_m2m_release(jpeg->m2m_dev);
+ v4l2_device_unregister(&jpeg->v4l2_dev);
+
+ clk_disable(jpeg->clk);
+ clk_put(jpeg->clk);
+
+ free_irq(jpeg->irq, jpeg);
+
+ iounmap(jpeg->regs);
+
+ release_resource(jpeg->ioarea);
+ release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea));
+ kfree(jpeg);
+
+ return 0;
+}
+
+static int s5p_jpeg_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int s5p_jpeg_runtime_resume(struct device *dev)
+{
+ struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
+ /*
+ * JPEG IP allows storing two Huffman tables for each component
+ * We fill table 0 for each component
+ */
+ jpeg_set_hdctbl(jpeg->regs);
+ jpeg_set_hdctblg(jpeg->regs);
+ jpeg_set_hactbl(jpeg->regs);
+ jpeg_set_hactblg(jpeg->regs);
+ return 0;
+}
+
+static const struct dev_pm_ops s5p_jpeg_pm_ops = {
+ .runtime_suspend = s5p_jpeg_runtime_suspend,
+ .runtime_resume = s5p_jpeg_runtime_resume,
+};
+
+static struct platform_driver s5p_jpeg_driver = {
+ .probe = s5p_jpeg_probe,
+ .remove = s5p_jpeg_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = S5P_JPEG_M2M_NAME,
+ .pm = &s5p_jpeg_pm_ops,
+ },
+};
+
+static int __init
+s5p_jpeg_register(void)
+{
+ int ret;
+
+ pr_info("S5P JPEG V4L2 Driver, (c) 2011 Samsung Electronics\n");
+
+ ret = platform_driver_register(&s5p_jpeg_driver);
+
+ if (ret)
+ pr_err("%s: failed to register jpeg driver\n", __func__);
+
+ return ret;
+}
+
+static void __exit
+s5p_jpeg_unregister(void)
+{
+ platform_driver_unregister(&s5p_jpeg_driver);
+}
+
+module_init(s5p_jpeg_register);
+module_exit(s5p_jpeg_unregister);
+
+MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
+MODULE_DESCRIPTION("Samsung JPEG codec driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h
new file mode 100644
index 000000000000..38d7367f7a6d
--- /dev/null
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.h
@@ -0,0 +1,152 @@
+/* linux/drivers/media/video/s5p-jpeg/jpeg-core.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef JPEG_CORE_H_
+#define JPEG_CORE_H_
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+
+#define S5P_JPEG_M2M_NAME "s5p-jpeg"
+
+/* JPEG compression quality setting */
+#define S5P_JPEG_COMPR_QUAL_BEST 0
+#define S5P_JPEG_COMPR_QUAL_WORST 3
+
+/* JPEG RGB to YCbCr conversion matrix coefficients */
+#define S5P_JPEG_COEF11 0x4d
+#define S5P_JPEG_COEF12 0x97
+#define S5P_JPEG_COEF13 0x1e
+#define S5P_JPEG_COEF21 0x2c
+#define S5P_JPEG_COEF22 0x57
+#define S5P_JPEG_COEF23 0x83
+#define S5P_JPEG_COEF31 0x83
+#define S5P_JPEG_COEF32 0x6e
+#define S5P_JPEG_COEF33 0x13
+
+/* a selection of JPEG markers */
+#define TEM 0x01
+#define SOF0 0xc0
+#define RST 0xd0
+#define SOI 0xd8
+#define EOI 0xd9
+#define DHP 0xde
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE (1 << 0)
+#define MEM2MEM_OUTPUT (1 << 1)
+
+/**
+ * struct s5p_jpeg - JPEG IP abstraction
+ * @lock: the mutex protecting this structure
+ * @slock: spinlock protecting the device contexts
+ * @v4l2_dev: v4l2 device for mem2mem mode
+ * @vfd_encoder: video device node for encoder mem2mem mode
+ * @vfd_decoder: video device node for decoder mem2mem mode
+ * @m2m_dev: v4l2 mem2mem device data
+ * @ioarea: JPEG IP memory region
+ * @regs: JPEG IP registers mapping
+ * @irq: JPEG IP irq
+ * @clk: JPEG IP clock
+ * @dev: JPEG IP struct device
+ * @alloc_ctx: videobuf2 memory allocator's context
+ */
+struct s5p_jpeg {
+ struct mutex lock;
+ struct spinlock slock;
+
+ struct v4l2_device v4l2_dev;
+ struct video_device *vfd_encoder;
+ struct video_device *vfd_decoder;
+ struct v4l2_m2m_dev *m2m_dev;
+
+ struct resource *ioarea;
+ void __iomem *regs;
+ unsigned int irq;
+ struct clk *clk;
+ struct device *dev;
+ void *alloc_ctx;
+};
+
+/**
+ * struct jpeg_fmt - driver's internal color format data
+ * @name: format descritpion
+ * @fourcc: the fourcc code, 0 if not applicable
+ * @depth: number of bits per pixel
+ * @colplanes: number of color planes (1 for packed formats)
+ * @h_align: horizontal alignment order (align to 2^h_align)
+ * @v_align: vertical alignment order (align to 2^v_align)
+ * @types: types of queue this format is applicable to
+ */
+struct s5p_jpeg_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+ int colplanes;
+ int h_align;
+ int v_align;
+ u32 types;
+};
+
+/**
+ * s5p_jpeg_q_data - parameters of one queue
+ * @fmt: driver-specific format of this queue
+ * @w: image width
+ * @h: image height
+ * @size: image buffer size in bytes
+ */
+struct s5p_jpeg_q_data {
+ struct s5p_jpeg_fmt *fmt;
+ u32 w;
+ u32 h;
+ u32 size;
+};
+
+/**
+ * s5p_jpeg_ctx - the device context data
+ * @jpeg: JPEG IP device for this context
+ * @mode: compression (encode) operation or decompression (decode)
+ * @compr_quality: destination image quality in compression (encode) mode
+ * @m2m_ctx: mem2mem device context
+ * @out_q: source (output) queue information
+ * @cap_fmt: destination (capture) queue queue information
+ * @hdr_parsed: set if header has been parsed during decompression
+ * @ctrl_handler: controls handler
+ */
+struct s5p_jpeg_ctx {
+ struct s5p_jpeg *jpeg;
+ unsigned int mode;
+ unsigned short compr_quality;
+ unsigned short restart_interval;
+ unsigned short subsampling;
+ struct v4l2_m2m_ctx *m2m_ctx;
+ struct s5p_jpeg_q_data out_q;
+ struct s5p_jpeg_q_data cap_q;
+ struct v4l2_fh fh;
+ bool hdr_parsed;
+ struct v4l2_ctrl_handler ctrl_handler;
+};
+
+/**
+ * s5p_jpeg_buffer - description of memory containing input JPEG data
+ * @size: buffer size
+ * @curr: current position in the buffer
+ * @data: pointer to the data
+ */
+struct s5p_jpeg_buffer {
+ unsigned long size;
+ unsigned long curr;
+ unsigned long data;
+};
+
+#endif /* JPEG_CORE_H */
diff --git a/drivers/media/video/s5p-jpeg/jpeg-hw.h b/drivers/media/video/s5p-jpeg/jpeg-hw.h
new file mode 100644
index 000000000000..f12f0fdbde7c
--- /dev/null
+++ b/drivers/media/video/s5p-jpeg/jpeg-hw.h
@@ -0,0 +1,357 @@
+/* linux/drivers/media/video/s5p-jpeg/jpeg-hw.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * 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.
+ */
+#ifndef JPEG_HW_H_
+#define JPEG_HW_H_
+
+#include <linux/io.h>
+#include <linux/videodev2.h>
+
+#include "jpeg-hw.h"
+#include "jpeg-regs.h"
+
+#define S5P_JPEG_MIN_WIDTH 32
+#define S5P_JPEG_MIN_HEIGHT 32
+#define S5P_JPEG_MAX_WIDTH 8192
+#define S5P_JPEG_MAX_HEIGHT 8192
+#define S5P_JPEG_ENCODE 0
+#define S5P_JPEG_DECODE 1
+#define S5P_JPEG_RAW_IN_565 0
+#define S5P_JPEG_RAW_IN_422 1
+#define S5P_JPEG_RAW_OUT_422 0
+#define S5P_JPEG_RAW_OUT_420 1
+
+static inline void jpeg_reset(void __iomem *regs)
+{
+ unsigned long reg;
+
+ writel(1, regs + S5P_JPG_SW_RESET);
+ reg = readl(regs + S5P_JPG_SW_RESET);
+ /* no other way but polling for when JPEG IP becomes operational */
+ while (reg != 0) {
+ cpu_relax();
+ reg = readl(regs + S5P_JPG_SW_RESET);
+ }
+}
+
+static inline void jpeg_poweron(void __iomem *regs)
+{
+ writel(S5P_POWER_ON, regs + S5P_JPGCLKCON);
+}
+
+static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
+{
+ unsigned long reg, m;
+
+ m = S5P_MOD_SEL_565;
+ if (mode == S5P_JPEG_RAW_IN_565)
+ m = S5P_MOD_SEL_565;
+ else if (mode == S5P_JPEG_RAW_IN_422)
+ m = S5P_MOD_SEL_422;
+
+ reg = readl(regs + S5P_JPGCMOD);
+ reg &= ~S5P_MOD_SEL_MASK;
+ reg |= m;
+ writel(reg, regs + S5P_JPGCMOD);
+}
+
+static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGCMOD);
+ if (y16)
+ reg |= S5P_MODE_Y16;
+ else
+ reg &= ~S5P_MODE_Y16_MASK;
+ writel(reg, regs + S5P_JPGCMOD);
+}
+
+static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
+{
+ unsigned long reg, m;
+
+ m = S5P_PROC_MODE_DECOMPR;
+ if (mode == S5P_JPEG_ENCODE)
+ m = S5P_PROC_MODE_COMPR;
+ else
+ m = S5P_PROC_MODE_DECOMPR;
+ reg = readl(regs + S5P_JPGMOD);
+ reg &= ~S5P_PROC_MODE_MASK;
+ reg |= m;
+ writel(reg, regs + S5P_JPGMOD);
+}
+
+static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
+{
+ unsigned long reg, m;
+
+ if (mode == V4L2_JPEG_CHROMA_SUBSAMPLING_420)
+ m = S5P_SUBSAMPLING_MODE_420;
+ else
+ m = S5P_SUBSAMPLING_MODE_422;
+
+ reg = readl(regs + S5P_JPGMOD);
+ reg &= ~S5P_SUBSAMPLING_MODE_MASK;
+ reg |= m;
+ writel(reg, regs + S5P_JPGMOD);
+}
+
+static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs)
+{
+ return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK;
+}
+
+static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGDRI_U);
+ reg &= ~0xff;
+ reg |= (dri >> 8) & 0xff;
+ writel(reg, regs + S5P_JPGDRI_U);
+
+ reg = readl(regs + S5P_JPGDRI_L);
+ reg &= ~0xff;
+ reg |= dri & 0xff;
+ writel(reg, regs + S5P_JPGDRI_L);
+}
+
+static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_QTBL);
+ reg &= ~S5P_QT_NUMt_MASK(t);
+ reg |= (n << S5P_QT_NUMt_SHIFT(t)) & S5P_QT_NUMt_MASK(t);
+ writel(reg, regs + S5P_JPG_QTBL);
+}
+
+static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_HTBL);
+ reg &= ~S5P_HT_NUMt_AC_MASK(t);
+ /* this driver uses table 0 for all color components */
+ reg |= (0 << S5P_HT_NUMt_AC_SHIFT(t)) & S5P_HT_NUMt_AC_MASK(t);
+ writel(reg, regs + S5P_JPG_HTBL);
+}
+
+static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_HTBL);
+ reg &= ~S5P_HT_NUMt_DC_MASK(t);
+ /* this driver uses table 0 for all color components */
+ reg |= (0 << S5P_HT_NUMt_DC_SHIFT(t)) & S5P_HT_NUMt_DC_MASK(t);
+ writel(reg, regs + S5P_JPG_HTBL);
+}
+
+static inline void jpeg_y(void __iomem *regs, unsigned int y)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGY_U);
+ reg &= ~0xff;
+ reg |= (y >> 8) & 0xff;
+ writel(reg, regs + S5P_JPGY_U);
+
+ reg = readl(regs + S5P_JPGY_L);
+ reg &= ~0xff;
+ reg |= y & 0xff;
+ writel(reg, regs + S5P_JPGY_L);
+}
+
+static inline void jpeg_x(void __iomem *regs, unsigned int x)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGX_U);
+ reg &= ~0xff;
+ reg |= (x >> 8) & 0xff;
+ writel(reg, regs + S5P_JPGX_U);
+
+ reg = readl(regs + S5P_JPGX_L);
+ reg &= ~0xff;
+ reg |= x & 0xff;
+ writel(reg, regs + S5P_JPGX_L);
+}
+
+static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGINTSE);
+ reg &= ~S5P_RSTm_INT_EN_MASK;
+ if (enable)
+ reg |= S5P_RSTm_INT_EN;
+ writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGINTSE);
+ reg &= ~S5P_DATA_NUM_INT_EN_MASK;
+ if (enable)
+ reg |= S5P_DATA_NUM_INT_EN;
+ writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGINTSE);
+ reg &= ~S5P_FINAL_MCU_NUM_INT_EN_MASK;
+ if (enbl)
+ reg |= S5P_FINAL_MCU_NUM_INT_EN;
+ writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_TIMER_SE);
+ reg |= S5P_TIMER_INT_EN;
+ reg &= ~S5P_TIMER_INIT_MASK;
+ reg |= val & S5P_TIMER_INIT_MASK;
+ writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline void jpeg_timer_disable(void __iomem *regs)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_TIMER_SE);
+ reg &= ~S5P_TIMER_INT_EN_MASK;
+ writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline int jpeg_timer_stat(void __iomem *regs)
+{
+ return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK)
+ >> S5P_TIMER_INT_STAT_SHIFT);
+}
+
+static inline void jpeg_clear_timer_stat(void __iomem *regs)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_TIMER_SE);
+ reg &= ~S5P_TIMER_INT_STAT_MASK;
+ writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
+ reg &= ~S5P_ENC_STREAM_BOUND_MASK;
+ reg |= S5P_ENC_STREAM_INT_EN;
+ reg |= size & S5P_ENC_STREAM_BOUND_MASK;
+ writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
+}
+
+static inline int jpeg_enc_stream_stat(void __iomem *regs)
+{
+ return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) &
+ S5P_ENC_STREAM_INT_STAT_MASK);
+}
+
+static inline void jpeg_clear_enc_stream_stat(void __iomem *regs)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
+ reg &= ~S5P_ENC_STREAM_INT_MASK;
+ writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
+}
+
+static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format)
+{
+ unsigned long reg, f;
+
+ f = S5P_DEC_OUT_FORMAT_422;
+ if (format == S5P_JPEG_RAW_OUT_422)
+ f = S5P_DEC_OUT_FORMAT_422;
+ else if (format == S5P_JPEG_RAW_OUT_420)
+ f = S5P_DEC_OUT_FORMAT_420;
+ reg = readl(regs + S5P_JPG_OUTFORM);
+ reg &= ~S5P_DEC_OUT_FORMAT_MASK;
+ reg |= f;
+ writel(reg, regs + S5P_JPG_OUTFORM);
+}
+
+static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr)
+{
+ writel(addr, regs + S5P_JPG_JPGADR);
+}
+
+static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr)
+{
+ writel(addr, regs + S5P_JPG_IMGADR);
+}
+
+static inline void jpeg_coef(void __iomem *regs, unsigned int i,
+ unsigned int j, unsigned int coef)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_COEF(i));
+ reg &= ~S5P_COEFn_MASK(j);
+ reg |= (coef << S5P_COEFn_SHIFT(j)) & S5P_COEFn_MASK(j);
+ writel(reg, regs + S5P_JPG_COEF(i));
+}
+
+static inline void jpeg_start(void __iomem *regs)
+{
+ writel(1, regs + S5P_JSTART);
+}
+
+static inline int jpeg_result_stat_ok(void __iomem *regs)
+{
+ return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK)
+ >> S5P_RESULT_STAT_SHIFT);
+}
+
+static inline int jpeg_stream_stat_ok(void __iomem *regs)
+{
+ return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK)
+ >> S5P_STREAM_STAT_SHIFT);
+}
+
+static inline void jpeg_clear_int(void __iomem *regs)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGINTST);
+ writel(S5P_INT_RELEASE, regs + S5P_JPGCOM);
+ reg = readl(regs + S5P_JPGOPR);
+}
+
+static inline unsigned int jpeg_compressed_size(void __iomem *regs)
+{
+ unsigned long jpeg_size = 0;
+
+ jpeg_size |= (readl(regs + S5P_JPGCNT_U) & 0xff) << 16;
+ jpeg_size |= (readl(regs + S5P_JPGCNT_M) & 0xff) << 8;
+ jpeg_size |= (readl(regs + S5P_JPGCNT_L) & 0xff);
+
+ return (unsigned int)jpeg_size;
+}
+
+#endif /* JPEG_HW_H_ */
diff --git a/drivers/media/video/s5p-jpeg/jpeg-regs.h b/drivers/media/video/s5p-jpeg/jpeg-regs.h
new file mode 100644
index 000000000000..91f4dd5f86dd
--- /dev/null
+++ b/drivers/media/video/s5p-jpeg/jpeg-regs.h
@@ -0,0 +1,170 @@
+/* linux/drivers/media/video/s5p-jpeg/jpeg-regs.h
+ *
+ * Register definition file for Samsung JPEG codec driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef JPEG_REGS_H_
+#define JPEG_REGS_H_
+
+/* JPEG mode register */
+#define S5P_JPGMOD 0x00
+#define S5P_PROC_MODE_MASK (0x1 << 3)
+#define S5P_PROC_MODE_DECOMPR (0x1 << 3)
+#define S5P_PROC_MODE_COMPR (0x0 << 3)
+#define S5P_SUBSAMPLING_MODE_MASK 0x7
+#define S5P_SUBSAMPLING_MODE_444 (0x0 << 0)
+#define S5P_SUBSAMPLING_MODE_422 (0x1 << 0)
+#define S5P_SUBSAMPLING_MODE_420 (0x2 << 0)
+#define S5P_SUBSAMPLING_MODE_GRAY (0x3 << 0)
+
+/* JPEG operation status register */
+#define S5P_JPGOPR 0x04
+
+/* Quantization tables*/
+#define S5P_JPG_QTBL 0x08
+#define S5P_QT_NUMt_SHIFT(t) (((t) - 1) << 1)
+#define S5P_QT_NUMt_MASK(t) (0x3 << S5P_QT_NUMt_SHIFT(t))
+
+/* Huffman tables */
+#define S5P_JPG_HTBL 0x0c
+#define S5P_HT_NUMt_AC_SHIFT(t) (((t) << 1) - 1)
+#define S5P_HT_NUMt_AC_MASK(t) (0x1 << S5P_HT_NUMt_AC_SHIFT(t))
+
+#define S5P_HT_NUMt_DC_SHIFT(t) (((t) - 1) << 1)
+#define S5P_HT_NUMt_DC_MASK(t) (0x1 << S5P_HT_NUMt_DC_SHIFT(t))
+
+/* JPEG restart interval register upper byte */
+#define S5P_JPGDRI_U 0x10
+
+/* JPEG restart interval register lower byte */
+#define S5P_JPGDRI_L 0x14
+
+/* JPEG vertical resolution register upper byte */
+#define S5P_JPGY_U 0x18
+
+/* JPEG vertical resolution register lower byte */
+#define S5P_JPGY_L 0x1c
+
+/* JPEG horizontal resolution register upper byte */
+#define S5P_JPGX_U 0x20
+
+/* JPEG horizontal resolution register lower byte */
+#define S5P_JPGX_L 0x24
+
+/* JPEG byte count register upper byte */
+#define S5P_JPGCNT_U 0x28
+
+/* JPEG byte count register middle byte */
+#define S5P_JPGCNT_M 0x2c
+
+/* JPEG byte count register lower byte */
+#define S5P_JPGCNT_L 0x30
+
+/* JPEG interrupt setting register */
+#define S5P_JPGINTSE 0x34
+#define S5P_RSTm_INT_EN_MASK (0x1 << 7)
+#define S5P_RSTm_INT_EN (0x1 << 7)
+#define S5P_DATA_NUM_INT_EN_MASK (0x1 << 6)
+#define S5P_DATA_NUM_INT_EN (0x1 << 6)
+#define S5P_FINAL_MCU_NUM_INT_EN_MASK (0x1 << 5)
+#define S5P_FINAL_MCU_NUM_INT_EN (0x1 << 5)
+
+/* JPEG interrupt status register */
+#define S5P_JPGINTST 0x38
+#define S5P_RESULT_STAT_SHIFT 6
+#define S5P_RESULT_STAT_MASK (0x1 << S5P_RESULT_STAT_SHIFT)
+#define S5P_STREAM_STAT_SHIFT 5
+#define S5P_STREAM_STAT_MASK (0x1 << S5P_STREAM_STAT_SHIFT)
+
+/* JPEG command register */
+#define S5P_JPGCOM 0x4c
+#define S5P_INT_RELEASE (0x1 << 2)
+
+/* Raw image data r/w address register */
+#define S5P_JPG_IMGADR 0x50
+
+/* JPEG file r/w address register */
+#define S5P_JPG_JPGADR 0x58
+
+/* Coefficient for RGB-to-YCbCr converter register */
+#define S5P_JPG_COEF(n) (0x5c + (((n) - 1) << 2))
+#define S5P_COEFn_SHIFT(j) ((3 - (j)) << 3)
+#define S5P_COEFn_MASK(j) (0xff << S5P_COEFn_SHIFT(j))
+
+/* JPEG color mode register */
+#define S5P_JPGCMOD 0x68
+#define S5P_MOD_SEL_MASK (0x7 << 5)
+#define S5P_MOD_SEL_422 (0x1 << 5)
+#define S5P_MOD_SEL_565 (0x2 << 5)
+#define S5P_MODE_Y16_MASK (0x1 << 1)
+#define S5P_MODE_Y16 (0x1 << 1)
+
+/* JPEG clock control register */
+#define S5P_JPGCLKCON 0x6c
+#define S5P_CLK_DOWN_READY (0x1 << 1)
+#define S5P_POWER_ON (0x1 << 0)
+
+/* JPEG start register */
+#define S5P_JSTART 0x70
+
+/* JPEG SW reset register */
+#define S5P_JPG_SW_RESET 0x78
+
+/* JPEG timer setting register */
+#define S5P_JPG_TIMER_SE 0x7c
+#define S5P_TIMER_INT_EN_MASK (0x1 << 31)
+#define S5P_TIMER_INT_EN (0x1 << 31)
+#define S5P_TIMER_INIT_MASK 0x7fffffff
+
+/* JPEG timer status register */
+#define S5P_JPG_TIMER_ST 0x80
+#define S5P_TIMER_INT_STAT_SHIFT 31
+#define S5P_TIMER_INT_STAT_MASK (0x1 << S5P_TIMER_INT_STAT_SHIFT)
+#define S5P_TIMER_CNT_SHIFT 0
+#define S5P_TIMER_CNT_MASK 0x7fffffff
+
+/* JPEG decompression output format register */
+#define S5P_JPG_OUTFORM 0x88
+#define S5P_DEC_OUT_FORMAT_MASK (0x1 << 0)
+#define S5P_DEC_OUT_FORMAT_422 (0x0 << 0)
+#define S5P_DEC_OUT_FORMAT_420 (0x1 << 0)
+
+/* JPEG version register */
+#define S5P_JPG_VERSION 0x8c
+
+/* JPEG compressed stream size interrupt setting register */
+#define S5P_JPG_ENC_STREAM_INTSE 0x98
+#define S5P_ENC_STREAM_INT_MASK (0x1 << 24)
+#define S5P_ENC_STREAM_INT_EN (0x1 << 24)
+#define S5P_ENC_STREAM_BOUND_MASK 0xffffff
+
+/* JPEG compressed stream size interrupt status register */
+#define S5P_JPG_ENC_STREAM_INTST 0x9c
+#define S5P_ENC_STREAM_INT_STAT_MASK 0x1
+
+/* JPEG quantizer table register */
+#define S5P_JPG_QTBL_CONTENT(n) (0x400 + (n) * 0x100)
+
+/* JPEG DC Huffman table register */
+#define S5P_JPG_HDCTBL(n) (0x800 + (n) * 0x400)
+
+/* JPEG DC Huffman table register */
+#define S5P_JPG_HDCTBLG(n) (0x840 + (n) * 0x400)
+
+/* JPEG AC Huffman table register */
+#define S5P_JPG_HACTBL(n) (0x880 + (n) * 0x400)
+
+/* JPEG AC Huffman table register */
+#define S5P_JPG_HACTBLG(n) (0x8c0 + (n) * 0x400)
+
+#endif /* JPEG_REGS_H_ */
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc.c b/drivers/media/video/s5p-mfc/s5p_mfc.c
index 8be8b54eb749..83fe461af263 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc.c
@@ -18,7 +18,6 @@
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/version.h>
#include <linux/videodev2.h>
#include <linux/workqueue.h>
#include <media/videobuf2-core.h>
@@ -475,7 +474,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
ctx->mv_size = 0;
}
ctx->dpb_count = s5p_mfc_get_dpb_count();
- if (ctx->img_width == 0 || ctx->img_width == 0)
+ if (ctx->img_width == 0 || ctx->img_height == 0)
ctx->state = MFCINST_ERROR;
else
ctx->state = MFCINST_HEAD_PARSED;
@@ -1245,27 +1244,7 @@ static struct platform_driver s5p_mfc_driver = {
},
};
-static char banner[] __initdata =
- "S5P MFC V4L2 Driver, (C) 2011 Samsung Electronics\n";
-
-static int __init s5p_mfc_init(void)
-{
- int ret;
-
- pr_info("%s", banner);
- ret = platform_driver_register(&s5p_mfc_driver);
- if (ret)
- pr_err("Platform device registration failed.\n");
- return ret;
-}
-
-static void __exit s5p_mfc_exit(void)
-{
- platform_driver_unregister(&s5p_mfc_driver);
-}
-
-module_init(s5p_mfc_init);
-module_exit(s5p_mfc_exit);
+module_platform_driver(s5p_mfc_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
index 844a4d7797bc..c25ec022d267 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
@@ -165,7 +165,7 @@ static struct mfc_control controls[] = {
.maximum = 32,
.step = 1,
.default_value = 1,
- .flags = V4L2_CTRL_FLAG_VOLATILE,
+ .is_volatile = 1,
},
};
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
index f6a3035c4fb7..738a607be43c 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
@@ -41,15 +41,29 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME);
if (IS_ERR(pm->clock_gate)) {
mfc_err("Failed to get clock-gating control\n");
- ret = -ENOENT;
+ ret = PTR_ERR(pm->clock_gate);
goto err_g_ip_clk;
}
+
+ ret = clk_prepare(pm->clock_gate);
+ if (ret) {
+ mfc_err("Failed to preapre clock-gating control\n");
+ goto err_p_ip_clk;
+ }
+
pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME);
if (IS_ERR(pm->clock)) {
mfc_err("Failed to get MFC clock\n");
- ret = -ENOENT;
+ ret = PTR_ERR(pm->clock);
goto err_g_ip_clk_2;
}
+
+ ret = clk_prepare(pm->clock);
+ if (ret) {
+ mfc_err("Failed to prepare MFC clock\n");
+ goto err_p_ip_clk_2;
+ }
+
atomic_set(&pm->power, 0);
#ifdef CONFIG_PM_RUNTIME
pm->device = &dev->plat_dev->dev;
@@ -59,7 +73,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
atomic_set(&clk_ref, 0);
#endif
return 0;
+err_p_ip_clk_2:
+ clk_put(pm->clock);
err_g_ip_clk_2:
+ clk_unprepare(pm->clock_gate);
+err_p_ip_clk:
clk_put(pm->clock_gate);
err_g_ip_clk:
return ret;
@@ -67,7 +85,9 @@ err_g_ip_clk:
void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
{
+ clk_unprepare(pm->clock_gate);
clk_put(pm->clock_gate);
+ clk_unprepare(pm->clock);
clk_put(pm->clock);
#ifdef CONFIG_PM_RUNTIME
pm_runtime_disable(pm->device);
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
index f2a09779ec8f..f248b2856720 100644
--- a/drivers/media/video/s5p-tv/Kconfig
+++ b/drivers/media/video/s5p-tv/Kconfig
@@ -46,6 +46,16 @@ config VIDEO_SAMSUNG_S5P_HDMIPHY
as module. It is an I2C driver, that exposes a V4L2
subdev for use by other drivers.
+config VIDEO_SAMSUNG_S5P_SII9234
+ tristate "Samsung SII9234 Driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+ depends on VIDEO_SAMSUNG_S5P_TV
+ help
+ Say Y here if you want support for the MHL interface
+ in S5P Samsung SoC. The driver can be compiled
+ as module. It is an I2C driver, that exposes a V4L2
+ subdev for use by other drivers.
+
config VIDEO_SAMSUNG_S5P_SDO
tristate "Samsung Analog TV Driver"
depends on VIDEO_DEV && VIDEO_V4L2
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile
index 37e4c17663b4..f49e756a2fde 100644
--- a/drivers/media/video/s5p-tv/Makefile
+++ b/drivers/media/video/s5p-tv/Makefile
@@ -8,6 +8,8 @@
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o
s5p-hdmiphy-y += hdmiphy_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SII9234) += s5p-sii9234.o
+s5p-sii9234-y += sii9234_drv.o
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
s5p-hdmi-y += hdmi_drv.o
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c
index 0279e6e89feb..4865d25a0e57 100644
--- a/drivers/media/video/s5p-tv/hdmi_drv.c
+++ b/drivers/media/video/s5p-tv/hdmi_drv.c
@@ -30,6 +30,7 @@
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
+#include <media/s5p_hdmi.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
@@ -66,6 +67,8 @@ struct hdmi_device {
struct v4l2_device v4l2_dev;
/** subdev of HDMIPHY interface */
struct v4l2_subdev *phy_sd;
+ /** subdev of MHL interface */
+ struct v4l2_subdev *mhl_sd;
/** configuration of current graphic mode */
const struct hdmi_preset_conf *cur_conf;
/** current preset */
@@ -74,10 +77,6 @@ struct hdmi_device {
struct hdmi_resources res;
};
-struct hdmi_driver_data {
- int hdmiphy_bus;
-};
-
struct hdmi_tg_regs {
u8 cmd;
u8 h_fsz_l;
@@ -129,23 +128,11 @@ struct hdmi_preset_conf {
struct v4l2_mbus_framefmt mbus_fmt;
};
-/* I2C module and id for HDMIPHY */
-static struct i2c_board_info hdmiphy_info = {
- I2C_BOARD_INFO("hdmiphy", 0x38),
-};
-
-static struct hdmi_driver_data hdmi_driver_data[] = {
- { .hdmiphy_bus = 3 },
- { .hdmiphy_bus = 8 },
-};
-
static struct platform_device_id hdmi_driver_types[] = {
{
.name = "s5pv210-hdmi",
- .driver_data = (unsigned long)&hdmi_driver_data[0],
}, {
.name = "exynos4-hdmi",
- .driver_data = (unsigned long)&hdmi_driver_data[1],
}, {
/* end node */
}
@@ -587,7 +574,15 @@ static int hdmi_streamon(struct hdmi_device *hdev)
if (tries == 0) {
dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
- hdmi_dumpregs(hdev, "s_stream");
+ hdmi_dumpregs(hdev, "hdmiphy - s_stream");
+ return -EIO;
+ }
+
+ /* starting MHL */
+ ret = v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 1);
+ if (hdev->mhl_sd && ret) {
+ v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+ hdmi_dumpregs(hdev, "mhl - s_stream");
return -EIO;
}
@@ -618,6 +613,7 @@ static int hdmi_streamoff(struct hdmi_device *hdev)
clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
clk_enable(res->sclk_hdmi);
+ v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 0);
v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
hdmi_dumpregs(hdev, "streamoff");
@@ -739,6 +735,7 @@ static int hdmi_runtime_suspend(struct device *dev)
struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
dev_dbg(dev, "%s\n", __func__);
+ v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0);
hdmi_resource_poweroff(&hdev->res);
return 0;
}
@@ -757,6 +754,11 @@ static int hdmi_runtime_resume(struct device *dev)
if (ret)
goto fail;
+ /* starting MHL */
+ ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1);
+ if (hdev->mhl_sd && ret)
+ goto fail;
+
dev_dbg(dev, "poweron succeed\n");
return 0;
@@ -838,8 +840,8 @@ static int hdmi_resources_init(struct hdmi_device *hdev)
dev_err(dev, "failed to get clock 'hdmiphy'\n");
goto fail;
}
- res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
- sizeof res->regul_bulk[0], GFP_KERNEL);
+ res->regul_bulk = kcalloc(ARRAY_SIZE(supply),
+ sizeof(res->regul_bulk[0]), GFP_KERNEL);
if (!res->regul_bulk) {
dev_err(dev, "failed to get memory for regulators\n");
goto fail;
@@ -867,15 +869,21 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
- struct i2c_adapter *phy_adapter;
+ struct i2c_adapter *adapter;
struct v4l2_subdev *sd;
struct hdmi_device *hdmi_dev = NULL;
- struct hdmi_driver_data *drv_data;
+ struct s5p_hdmi_platform_data *pdata = dev->platform_data;
int ret;
dev_dbg(dev, "probe start\n");
- hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "platform data is missing\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(*hdmi_dev), GFP_KERNEL);
if (!hdmi_dev) {
dev_err(dev, "out of memory\n");
ret = -ENOMEM;
@@ -886,7 +894,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
ret = hdmi_resources_init(hdmi_dev);
if (ret)
- goto fail_hdev;
+ goto fail;
/* mapping HDMI registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -896,24 +904,26 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
goto fail_init;
}
- hdmi_dev->regs = ioremap(res->start, resource_size(res));
+ hdmi_dev->regs = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
if (hdmi_dev->regs == NULL) {
dev_err(dev, "register mapping failed.\n");
ret = -ENXIO;
- goto fail_hdev;
+ goto fail_init;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
dev_err(dev, "get interrupt resource failed.\n");
ret = -ENXIO;
- goto fail_regs;
+ goto fail_init;
}
- ret = request_irq(res->start, hdmi_irq_handler, 0, "hdmi", hdmi_dev);
+ ret = devm_request_irq(&pdev->dev, res->start, hdmi_irq_handler, 0,
+ "hdmi", hdmi_dev);
if (ret) {
dev_err(dev, "request interrupt failed.\n");
- goto fail_regs;
+ goto fail_init;
}
hdmi_dev->irq = res->start;
@@ -924,28 +934,54 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
if (ret) {
dev_err(dev, "could not register v4l2 device.\n");
- goto fail_irq;
+ goto fail_init;
}
- drv_data = (struct hdmi_driver_data *)
- platform_get_device_id(pdev)->driver_data;
- phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus);
- if (phy_adapter == NULL) {
- dev_err(dev, "adapter request failed\n");
+ /* testing if hdmiphy info is present */
+ if (!pdata->hdmiphy_info) {
+ dev_err(dev, "hdmiphy info is missing in platform data\n");
+ ret = -ENXIO;
+ goto fail_vdev;
+ }
+
+ adapter = i2c_get_adapter(pdata->hdmiphy_bus);
+ if (adapter == NULL) {
+ dev_err(dev, "hdmiphy adapter request failed\n");
ret = -ENXIO;
goto fail_vdev;
}
hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
- phy_adapter, &hdmiphy_info, NULL);
+ adapter, pdata->hdmiphy_info, NULL);
/* on failure or not adapter is no longer useful */
- i2c_put_adapter(phy_adapter);
+ i2c_put_adapter(adapter);
if (hdmi_dev->phy_sd == NULL) {
dev_err(dev, "missing subdev for hdmiphy\n");
ret = -ENODEV;
goto fail_vdev;
}
+ /* initialization of MHL interface if present */
+ if (pdata->mhl_info) {
+ adapter = i2c_get_adapter(pdata->mhl_bus);
+ if (adapter == NULL) {
+ dev_err(dev, "MHL adapter request failed\n");
+ ret = -ENXIO;
+ goto fail_vdev;
+ }
+
+ hdmi_dev->mhl_sd = v4l2_i2c_new_subdev_board(
+ &hdmi_dev->v4l2_dev, adapter,
+ pdata->mhl_info, NULL);
+ /* on failure or not adapter is no longer useful */
+ i2c_put_adapter(adapter);
+ if (hdmi_dev->mhl_sd == NULL) {
+ dev_err(dev, "missing subdev for MHL\n");
+ ret = -ENODEV;
+ goto fail_vdev;
+ }
+ }
+
clk_enable(hdmi_dev->res.hdmi);
pm_runtime_enable(dev);
@@ -962,25 +998,16 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
/* storing subdev for call that have only access to struct device */
dev_set_drvdata(dev, sd);
- dev_info(dev, "probe sucessful\n");
+ dev_info(dev, "probe successful\n");
return 0;
fail_vdev:
v4l2_device_unregister(&hdmi_dev->v4l2_dev);
-fail_irq:
- free_irq(hdmi_dev->irq, hdmi_dev);
-
-fail_regs:
- iounmap(hdmi_dev->regs);
-
fail_init:
hdmi_resources_cleanup(hdmi_dev);
-fail_hdev:
- kfree(hdmi_dev);
-
fail:
dev_err(dev, "probe failed\n");
return ret;
@@ -996,11 +1023,8 @@ static int __devexit hdmi_remove(struct platform_device *pdev)
clk_disable(hdmi_dev->res.hdmi);
v4l2_device_unregister(&hdmi_dev->v4l2_dev);
disable_irq(hdmi_dev->irq);
- free_irq(hdmi_dev->irq, hdmi_dev);
- iounmap(hdmi_dev->regs);
hdmi_resources_cleanup(hdmi_dev);
- kfree(hdmi_dev);
- dev_info(dev, "remove sucessful\n");
+ dev_info(dev, "remove successful\n");
return 0;
}
@@ -1016,28 +1040,4 @@ static struct platform_driver hdmi_driver __refdata = {
}
};
-/* D R I V E R I N I T I A L I Z A T I O N */
-
-static int __init hdmi_init(void)
-{
- int ret;
- static const char banner[] __initdata = KERN_INFO \
- "Samsung HDMI output driver, "
- "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
- printk(banner);
-
- ret = platform_driver_register(&hdmi_driver);
- if (ret)
- printk(KERN_ERR "HDMI platform driver register failed\n");
-
- return ret;
-}
-module_init(hdmi_init);
-
-static void __exit hdmi_exit(void)
-{
- platform_driver_unregister(&hdmi_driver);
-}
-module_exit(hdmi_exit);
-
-
+module_platform_driver(hdmi_driver);
diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/video/s5p-tv/hdmiphy_drv.c
index 6693f4aff108..0afef77747e5 100644
--- a/drivers/media/video/s5p-tv/hdmiphy_drv.c
+++ b/drivers/media/video/s5p-tv/hdmiphy_drv.c
@@ -175,14 +175,4 @@ static struct i2c_driver hdmiphy_driver = {
.id_table = hdmiphy_id,
};
-static int __init hdmiphy_init(void)
-{
- return i2c_add_driver(&hdmiphy_driver);
-}
-module_init(hdmiphy_init);
-
-static void __exit hdmiphy_exit(void)
-{
- i2c_del_driver(&hdmiphy_driver);
-}
-module_exit(hdmiphy_exit);
+module_i2c_driver(hdmiphy_driver);
diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h
index 51ad59b30358..1597078c4a50 100644
--- a/drivers/media/video/s5p-tv/mixer.h
+++ b/drivers/media/video/s5p-tv/mixer.h
@@ -86,6 +86,17 @@ struct mxr_crop {
unsigned int field;
};
+/** stages of geometry operations */
+enum mxr_geometry_stage {
+ MXR_GEOMETRY_SINK,
+ MXR_GEOMETRY_COMPOSE,
+ MXR_GEOMETRY_CROP,
+ MXR_GEOMETRY_SOURCE,
+};
+
+/* flag indicating that offset should be 0 */
+#define MXR_NO_OFFSET 0x80000000
+
/** description of transformation from source to destination image */
struct mxr_geometry {
/** cropping for source image */
@@ -133,7 +144,8 @@ struct mxr_layer_ops {
/** streaming stop/start */
void (*stream_set)(struct mxr_layer *, int);
/** adjusting geometry */
- void (*fix_geometry)(struct mxr_layer *);
+ void (*fix_geometry)(struct mxr_layer *,
+ enum mxr_geometry_stage, unsigned long);
};
/** layer instance, a single window and content displayed on output */
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
index 00643094b221..a2c0c25ad130 100644
--- a/drivers/media/video/s5p-tv/mixer_drv.c
+++ b/drivers/media/video/s5p-tv/mixer_drv.c
@@ -444,7 +444,7 @@ static int __devexit mxr_remove(struct platform_device *pdev)
kfree(mdev);
- dev_info(dev, "remove sucessful\n");
+ dev_info(dev, "remove successful\n");
return 0;
}
diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/video/s5p-tv/mixer_grp_layer.c
index de8270c2b6e7..b93a21f5aa13 100644
--- a/drivers/media/video/s5p-tv/mixer_grp_layer.c
+++ b/drivers/media/video/s5p-tv/mixer_grp_layer.c
@@ -101,47 +101,132 @@ static void mxr_graph_format_set(struct mxr_layer *layer)
layer->fmt, &layer->geo);
}
-static void mxr_graph_fix_geometry(struct mxr_layer *layer)
+static inline unsigned int closest(unsigned int x, unsigned int a,
+ unsigned int b, unsigned long flags)
+{
+ unsigned int mid = (a + b) / 2;
+
+ /* choosing closest value with constraints according to table:
+ * -------------+-----+-----+-----+-------+
+ * flags | 0 | LE | GE | LE|GE |
+ * -------------+-----+-----+-----+-------+
+ * x <= a | a | a | a | a |
+ * a < x <= mid | a | a | b | a |
+ * mid < x < b | b | a | b | b |
+ * b <= x | b | b | b | b |
+ * -------------+-----+-----+-----+-------+
+ */
+
+ /* remove all non-constraint flags */
+ flags &= V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE;
+
+ if (x <= a)
+ return a;
+ if (x >= b)
+ return b;
+ if (flags == V4L2_SEL_FLAG_LE)
+ return a;
+ if (flags == V4L2_SEL_FLAG_GE)
+ return b;
+ if (x <= mid)
+ return a;
+ return b;
+}
+
+static inline unsigned int do_center(unsigned int center,
+ unsigned int size, unsigned int upper, unsigned int flags)
+{
+ unsigned int lower;
+
+ if (flags & MXR_NO_OFFSET)
+ return 0;
+
+ lower = center - min(center, size / 2);
+ return min(lower, upper - size);
+}
+
+static void mxr_graph_fix_geometry(struct mxr_layer *layer,
+ enum mxr_geometry_stage stage, unsigned long flags)
{
struct mxr_geometry *geo = &layer->geo;
+ struct mxr_crop *src = &geo->src;
+ struct mxr_crop *dst = &geo->dst;
+ unsigned int x_center, y_center;
- /* limit to boundary size */
- geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
- geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047);
- geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width);
- geo->src.width = min(geo->src.width, 2047U);
- /* not possible to crop of Y axis */
- geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1);
- geo->src.height = geo->src.full_height - geo->src.y_offset;
- /* limitting offset */
- geo->src.x_offset = min(geo->src.x_offset,
- geo->src.full_width - geo->src.width);
-
- /* setting position in output */
- geo->dst.width = min(geo->dst.width, geo->dst.full_width);
- geo->dst.height = min(geo->dst.height, geo->dst.full_height);
-
- /* Mixer supports only 1x and 2x scaling */
- if (geo->dst.width >= 2 * geo->src.width) {
- geo->x_ratio = 1;
- geo->dst.width = 2 * geo->src.width;
- } else {
- geo->x_ratio = 0;
- geo->dst.width = geo->src.width;
- }
+ switch (stage) {
- if (geo->dst.height >= 2 * geo->src.height) {
- geo->y_ratio = 1;
- geo->dst.height = 2 * geo->src.height;
- } else {
- geo->y_ratio = 0;
- geo->dst.height = geo->src.height;
- }
+ case MXR_GEOMETRY_SINK: /* nothing to be fixed here */
+ flags = 0;
+ /* fall through */
+
+ case MXR_GEOMETRY_COMPOSE:
+ /* remember center of the area */
+ x_center = dst->x_offset + dst->width / 2;
+ y_center = dst->y_offset + dst->height / 2;
+ /* round up/down to 2 multiple depending on flags */
+ if (flags & V4L2_SEL_FLAG_LE) {
+ dst->width = round_down(dst->width, 2);
+ dst->height = round_down(dst->height, 2);
+ } else {
+ dst->width = round_up(dst->width, 2);
+ dst->height = round_up(dst->height, 2);
+ }
+ /* assure that compose rect is inside display area */
+ dst->width = min(dst->width, dst->full_width);
+ dst->height = min(dst->height, dst->full_height);
+
+ /* ensure that compose is reachable using 2x scaling */
+ dst->width = min(dst->width, 2 * src->full_width);
+ dst->height = min(dst->height, 2 * src->full_height);
+
+ /* setup offsets */
+ dst->x_offset = do_center(x_center, dst->width,
+ dst->full_width, flags);
+ dst->y_offset = do_center(y_center, dst->height,
+ dst->full_height, flags);
+ flags = 0;
+ /* fall through */
- geo->dst.x_offset = min(geo->dst.x_offset,
- geo->dst.full_width - geo->dst.width);
- geo->dst.y_offset = min(geo->dst.y_offset,
- geo->dst.full_height - geo->dst.height);
+ case MXR_GEOMETRY_CROP:
+ /* remember center of the area */
+ x_center = src->x_offset + src->width / 2;
+ y_center = src->y_offset + src->height / 2;
+ /* ensure that cropping area lies inside the buffer */
+ if (src->full_width < dst->width)
+ src->width = dst->width / 2;
+ else
+ src->width = closest(src->width, dst->width / 2,
+ dst->width, flags);
+
+ if (src->width == dst->width)
+ geo->x_ratio = 0;
+ else
+ geo->x_ratio = 1;
+
+ if (src->full_height < dst->height)
+ src->height = dst->height / 2;
+ else
+ src->height = closest(src->height, dst->height / 2,
+ dst->height, flags);
+
+ if (src->height == dst->height)
+ geo->y_ratio = 0;
+ else
+ geo->y_ratio = 1;
+
+ /* setup offsets */
+ src->x_offset = do_center(x_center, src->width,
+ src->full_width, flags);
+ src->y_offset = do_center(y_center, src->height,
+ src->full_height, flags);
+ flags = 0;
+ /* fall through */
+ case MXR_GEOMETRY_SOURCE:
+ src->full_width = clamp_val(src->full_width,
+ src->width + src->x_offset, 32767);
+ src->full_height = clamp_val(src->full_height,
+ src->height + src->y_offset, 2047);
+ };
}
/* PUBLIC API */
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
index b47d0c06ecf5..f7ca5cc143c6 100644
--- a/drivers/media/video/s5p-tv/mixer_video.c
+++ b/drivers/media/video/s5p-tv/mixer_video.c
@@ -58,7 +58,6 @@ static struct v4l2_subdev *find_and_register_subdev(
}
done:
- put_driver(drv);
return sd;
}
@@ -170,18 +169,22 @@ static int mxr_querycap(struct file *file, void *priv,
return 0;
}
-/* Geometry handling */
-static void mxr_layer_geo_fix(struct mxr_layer *layer)
+static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
{
- struct mxr_device *mdev = layer->mdev;
- struct v4l2_mbus_framefmt mbus_fmt;
-
- /* TODO: add some dirty flag to avoid unnecessary adjustments */
- mxr_get_mbus_fmt(mdev, &mbus_fmt);
- layer->geo.dst.full_width = mbus_fmt.width;
- layer->geo.dst.full_height = mbus_fmt.height;
- layer->geo.dst.field = mbus_fmt.field;
- layer->ops.fix_geometry(layer);
+ mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
+ geo->src.full_width, geo->src.full_height);
+ mxr_dbg(mdev, "src.size = (%u, %u)\n",
+ geo->src.width, geo->src.height);
+ mxr_dbg(mdev, "src.offset = (%u, %u)\n",
+ geo->src.x_offset, geo->src.y_offset);
+ mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
+ geo->dst.full_width, geo->dst.full_height);
+ mxr_dbg(mdev, "dst.size = (%u, %u)\n",
+ geo->dst.width, geo->dst.height);
+ mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
+ geo->dst.x_offset, geo->dst.y_offset);
+ mxr_dbg(mdev, "ratio = (%u, %u)\n",
+ geo->x_ratio, geo->y_ratio);
}
static void mxr_layer_default_geo(struct mxr_layer *layer)
@@ -204,27 +207,29 @@ static void mxr_layer_default_geo(struct mxr_layer *layer)
layer->geo.src.width = layer->geo.src.full_width;
layer->geo.src.height = layer->geo.src.full_height;
- layer->ops.fix_geometry(layer);
+ mxr_geometry_dump(mdev, &layer->geo);
+ layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0);
+ mxr_geometry_dump(mdev, &layer->geo);
}
-static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
+static void mxr_layer_update_output(struct mxr_layer *layer)
{
- mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
- geo->src.full_width, geo->src.full_height);
- mxr_dbg(mdev, "src.size = (%u, %u)\n",
- geo->src.width, geo->src.height);
- mxr_dbg(mdev, "src.offset = (%u, %u)\n",
- geo->src.x_offset, geo->src.y_offset);
- mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
- geo->dst.full_width, geo->dst.full_height);
- mxr_dbg(mdev, "dst.size = (%u, %u)\n",
- geo->dst.width, geo->dst.height);
- mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
- geo->dst.x_offset, geo->dst.y_offset);
- mxr_dbg(mdev, "ratio = (%u, %u)\n",
- geo->x_ratio, geo->y_ratio);
-}
+ struct mxr_device *mdev = layer->mdev;
+ struct v4l2_mbus_framefmt mbus_fmt;
+
+ mxr_get_mbus_fmt(mdev, &mbus_fmt);
+ /* checking if update is needed */
+ if (layer->geo.dst.full_width == mbus_fmt.width &&
+ layer->geo.dst.full_height == mbus_fmt.width)
+ return;
+ layer->geo.dst.full_width = mbus_fmt.width;
+ layer->geo.dst.full_height = mbus_fmt.height;
+ layer->geo.dst.field = mbus_fmt.field;
+ layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0);
+
+ mxr_geometry_dump(mdev, &layer->geo);
+}
static const struct mxr_format *find_format_by_fourcc(
struct mxr_layer *layer, unsigned long fourcc);
@@ -249,37 +254,6 @@ static int mxr_enum_fmt(struct file *file, void *priv,
return 0;
}
-static int mxr_s_fmt(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct mxr_layer *layer = video_drvdata(file);
- const struct mxr_format *fmt;
- struct v4l2_pix_format_mplane *pix;
- struct mxr_device *mdev = layer->mdev;
- struct mxr_geometry *geo = &layer->geo;
-
- mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
-
- pix = &f->fmt.pix_mp;
- fmt = find_format_by_fourcc(layer, pix->pixelformat);
- if (fmt == NULL) {
- mxr_warn(mdev, "not recognized fourcc: %08x\n",
- pix->pixelformat);
- return -EINVAL;
- }
- layer->fmt = fmt;
- geo->src.full_width = pix->width;
- geo->src.width = pix->width;
- geo->src.full_height = pix->height;
- geo->src.height = pix->height;
- /* assure consistency of geometry */
- mxr_layer_geo_fix(layer);
- mxr_dbg(mdev, "width=%u height=%u span=%u\n",
- geo->src.width, geo->src.height, geo->src.full_width);
-
- return 0;
-}
-
static unsigned int divup(unsigned int divident, unsigned int divisor)
{
return (divident + divisor - 1) / divisor;
@@ -299,6 +273,10 @@ static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
{
int i;
+ /* checking if nothing to fill */
+ if (!planes)
+ return;
+
memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
for (i = 0; i < fmt->num_planes; ++i) {
struct v4l2_plane_pix_format *plane = planes
@@ -332,73 +310,194 @@ static int mxr_g_fmt(struct file *file, void *priv,
return 0;
}
-static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo,
- enum v4l2_buf_type type)
-{
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- return &geo->dst;
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- return &geo->src;
- default:
- return NULL;
- }
-}
-
-static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+static int mxr_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
{
struct mxr_layer *layer = video_drvdata(file);
- struct mxr_crop *crop;
+ const struct mxr_format *fmt;
+ struct v4l2_pix_format_mplane *pix;
+ struct mxr_device *mdev = layer->mdev;
+ struct mxr_geometry *geo = &layer->geo;
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
- crop = choose_crop_by_type(&layer->geo, a->type);
- if (crop == NULL)
+ mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+
+ pix = &f->fmt.pix_mp;
+ fmt = find_format_by_fourcc(layer, pix->pixelformat);
+ if (fmt == NULL) {
+ mxr_warn(mdev, "not recognized fourcc: %08x\n",
+ pix->pixelformat);
return -EINVAL;
- mxr_layer_geo_fix(layer);
- a->c.left = crop->x_offset;
- a->c.top = crop->y_offset;
- a->c.width = crop->width;
- a->c.height = crop->height;
+ }
+ layer->fmt = fmt;
+ /* set source size to highest accepted value */
+ geo->src.full_width = max(geo->dst.full_width, pix->width);
+ geo->src.full_height = max(geo->dst.full_height, pix->height);
+ layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0);
+ mxr_geometry_dump(mdev, &layer->geo);
+ /* set cropping to total visible screen */
+ geo->src.width = pix->width;
+ geo->src.height = pix->height;
+ geo->src.x_offset = 0;
+ geo->src.y_offset = 0;
+ /* assure consistency of geometry */
+ layer->ops.fix_geometry(layer, MXR_GEOMETRY_CROP, MXR_NO_OFFSET);
+ mxr_geometry_dump(mdev, &layer->geo);
+ /* set full size to lowest possible value */
+ geo->src.full_width = 0;
+ geo->src.full_height = 0;
+ layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0);
+ mxr_geometry_dump(mdev, &layer->geo);
+
+ /* returning results */
+ mxr_g_fmt(file, priv, f);
+
return 0;
}
-static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+static int mxr_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
{
struct mxr_layer *layer = video_drvdata(file);
- struct mxr_crop *crop;
+ struct mxr_geometry *geo = &layer->geo;
mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
- crop = choose_crop_by_type(&layer->geo, a->type);
- if (crop == NULL)
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_ACTIVE:
+ s->r.left = geo->src.x_offset;
+ s->r.top = geo->src.y_offset;
+ s->r.width = geo->src.width;
+ s->r.height = geo->src.height;
+ break;
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = geo->src.full_width;
+ s->r.height = geo->src.full_height;
+ break;
+ case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+ case V4L2_SEL_TGT_COMPOSE_PADDED:
+ s->r.left = geo->dst.x_offset;
+ s->r.top = geo->dst.y_offset;
+ s->r.width = geo->dst.width;
+ s->r.height = geo->dst.height;
+ break;
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = geo->dst.full_width;
+ s->r.height = geo->dst.full_height;
+ break;
+ default:
return -EINVAL;
- crop->x_offset = a->c.left;
- crop->y_offset = a->c.top;
- crop->width = a->c.width;
- crop->height = a->c.height;
- mxr_layer_geo_fix(layer);
+ }
+
return 0;
}
-static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+/* returns 1 if rectangle 'a' is inside 'b' */
+static int mxr_is_rect_inside(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+ if (a->left < b->left)
+ return 0;
+ if (a->top < b->top)
+ return 0;
+ if (a->left + a->width > b->left + b->width)
+ return 0;
+ if (a->top + a->height > b->top + b->height)
+ return 0;
+ return 1;
+}
+
+static int mxr_s_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
{
struct mxr_layer *layer = video_drvdata(file);
- struct mxr_crop *crop;
+ struct mxr_geometry *geo = &layer->geo;
+ struct mxr_crop *target = NULL;
+ enum mxr_geometry_stage stage;
+ struct mxr_geometry tmp;
+ struct v4l2_rect res;
- mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
- crop = choose_crop_by_type(&layer->geo, a->type);
- if (crop == NULL)
+ memset(&res, 0, sizeof res);
+
+ mxr_dbg(layer->mdev, "%s: rect: %dx%d@%d,%d\n", __func__,
+ s->r.width, s->r.height, s->r.left, s->r.top);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
return -EINVAL;
- mxr_layer_geo_fix(layer);
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = crop->full_width;
- a->bounds.top = crop->full_height;
- a->defrect = a->bounds;
- /* setting pixel aspect to 1/1 */
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
+
+ switch (s->target) {
+ /* ignore read-only targets */
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ res.width = geo->src.full_width;
+ res.height = geo->src.full_height;
+ break;
+
+ /* ignore read-only targets */
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ res.width = geo->dst.full_width;
+ res.height = geo->dst.full_height;
+ break;
+
+ case V4L2_SEL_TGT_CROP_ACTIVE:
+ target = &geo->src;
+ stage = MXR_GEOMETRY_CROP;
+ break;
+ case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+ case V4L2_SEL_TGT_COMPOSE_PADDED:
+ target = &geo->dst;
+ stage = MXR_GEOMETRY_COMPOSE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* apply change and update geometry if needed */
+ if (target) {
+ /* backup current geometry if setup fails */
+ memcpy(&tmp, geo, sizeof tmp);
+
+ /* apply requested selection */
+ target->x_offset = s->r.left;
+ target->y_offset = s->r.top;
+ target->width = s->r.width;
+ target->height = s->r.height;
+
+ layer->ops.fix_geometry(layer, stage, s->flags);
+
+ /* retrieve update selection rectangle */
+ res.left = target->x_offset;
+ res.top = target->y_offset;
+ res.width = target->width;
+ res.height = target->height;
+
+ mxr_geometry_dump(layer->mdev, &layer->geo);
+ }
+
+ /* checking if the rectangle satisfies constraints */
+ if ((s->flags & V4L2_SEL_FLAG_LE) && !mxr_is_rect_inside(&res, &s->r))
+ goto fail;
+ if ((s->flags & V4L2_SEL_FLAG_GE) && !mxr_is_rect_inside(&s->r, &res))
+ goto fail;
+
+ /* return result rectangle */
+ s->r = res;
+
return 0;
+fail:
+ /* restore old geometry, which is not touched if target is NULL */
+ if (target)
+ memcpy(geo, &tmp, sizeof tmp);
+ return -ERANGE;
}
static int mxr_enum_dv_presets(struct file *file, void *fh,
@@ -438,6 +537,8 @@ static int mxr_s_dv_preset(struct file *file, void *fh,
mutex_unlock(&mdev->mutex);
+ mxr_layer_update_output(layer);
+
/* any failure should return EINVAL according to V4L2 doc */
return ret ? -EINVAL : 0;
}
@@ -478,6 +579,8 @@ static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
mutex_unlock(&mdev->mutex);
+ mxr_layer_update_output(layer);
+
return ret ? -EINVAL : 0;
}
@@ -526,25 +629,27 @@ static int mxr_s_output(struct file *file, void *fh, unsigned int i)
struct video_device *vfd = video_devdata(file);
struct mxr_layer *layer = video_drvdata(file);
struct mxr_device *mdev = layer->mdev;
- int ret = 0;
if (i >= mdev->output_cnt || mdev->output[i] == NULL)
return -EINVAL;
mutex_lock(&mdev->mutex);
if (mdev->n_output > 0) {
- ret = -EBUSY;
- goto done;
+ mutex_unlock(&mdev->mutex);
+ return -EBUSY;
}
mdev->current_output = i;
vfd->tvnorms = 0;
v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
&vfd->tvnorms);
+ mutex_unlock(&mdev->mutex);
+
+ /* update layers geometry */
+ mxr_layer_update_output(layer);
+
mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
-done:
- mutex_unlock(&mdev->mutex);
- return ret;
+ return 0;
}
static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
@@ -633,10 +738,9 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
.vidioc_enum_output = mxr_enum_output,
.vidioc_s_output = mxr_s_output,
.vidioc_g_output = mxr_g_output,
- /* Crop ioctls */
- .vidioc_g_crop = mxr_g_crop,
- .vidioc_s_crop = mxr_s_crop,
- .vidioc_cropcap = mxr_cropcap,
+ /* selection ioctls */
+ .vidioc_g_selection = mxr_g_selection,
+ .vidioc_s_selection = mxr_s_selection,
};
static int mxr_video_open(struct file *file)
@@ -805,10 +909,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
/* block any changes in output configuration */
mxr_output_get(mdev);
- /* update layers geometry */
- mxr_layer_geo_fix(layer);
- mxr_geometry_dump(mdev, &layer->geo);
-
+ mxr_layer_update_output(layer);
layer->ops.format_set(layer);
/* enabling layer in hardware */
spin_lock_irqsave(&layer->enq_slock, flags);
diff --git a/drivers/media/video/s5p-tv/mixer_vp_layer.c b/drivers/media/video/s5p-tv/mixer_vp_layer.c
index f3bb2e34cb51..3d13a636877b 100644
--- a/drivers/media/video/s5p-tv/mixer_vp_layer.c
+++ b/drivers/media/video/s5p-tv/mixer_vp_layer.c
@@ -127,47 +127,77 @@ static void mxr_vp_format_set(struct mxr_layer *layer)
mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
}
-static void mxr_vp_fix_geometry(struct mxr_layer *layer)
+static inline unsigned int do_center(unsigned int center,
+ unsigned int size, unsigned int upper, unsigned int flags)
{
- struct mxr_geometry *geo = &layer->geo;
+ unsigned int lower;
+
+ if (flags & MXR_NO_OFFSET)
+ return 0;
+
+ lower = center - min(center, size / 2);
+ return min(lower, upper - size);
+}
- /* align horizontal size to 8 pixels */
- geo->src.full_width = ALIGN(geo->src.full_width, 8);
- /* limit to boundary size */
- geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
- geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
- geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
- geo->src.width = min(geo->src.width, 2047U);
- geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
- geo->src.height = min(geo->src.height, 2047U);
-
- /* setting size of output window */
- geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
- geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);
-
- /* ensure that scaling is in range 1/4x to 16x */
- if (geo->src.width >= 4 * geo->dst.width)
- geo->src.width = 4 * geo->dst.width;
- if (geo->dst.width >= 16 * geo->src.width)
- geo->dst.width = 16 * geo->src.width;
- if (geo->src.height >= 4 * geo->dst.height)
- geo->src.height = 4 * geo->dst.height;
- if (geo->dst.height >= 16 * geo->src.height)
- geo->dst.height = 16 * geo->src.height;
-
- /* setting scaling ratio */
- geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
- geo->y_ratio = (geo->src.height << 16) / geo->dst.height;
-
- /* adjust offsets */
- geo->src.x_offset = min(geo->src.x_offset,
- geo->src.full_width - geo->src.width);
- geo->src.y_offset = min(geo->src.y_offset,
- geo->src.full_height - geo->src.height);
- geo->dst.x_offset = min(geo->dst.x_offset,
- geo->dst.full_width - geo->dst.width);
- geo->dst.y_offset = min(geo->dst.y_offset,
- geo->dst.full_height - geo->dst.height);
+static void mxr_vp_fix_geometry(struct mxr_layer *layer,
+ enum mxr_geometry_stage stage, unsigned long flags)
+{
+ struct mxr_geometry *geo = &layer->geo;
+ struct mxr_crop *src = &geo->src;
+ struct mxr_crop *dst = &geo->dst;
+ unsigned long x_center, y_center;
+
+ switch (stage) {
+
+ case MXR_GEOMETRY_SINK: /* nothing to be fixed here */
+ case MXR_GEOMETRY_COMPOSE:
+ /* remember center of the area */
+ x_center = dst->x_offset + dst->width / 2;
+ y_center = dst->y_offset + dst->height / 2;
+
+ /* ensure that compose is reachable using 16x scaling */
+ dst->width = clamp(dst->width, 8U, 16 * src->full_width);
+ dst->height = clamp(dst->height, 1U, 16 * src->full_height);
+
+ /* setup offsets */
+ dst->x_offset = do_center(x_center, dst->width,
+ dst->full_width, flags);
+ dst->y_offset = do_center(y_center, dst->height,
+ dst->full_height, flags);
+ flags = 0; /* remove possible MXR_NO_OFFSET flag */
+ /* fall through */
+ case MXR_GEOMETRY_CROP:
+ /* remember center of the area */
+ x_center = src->x_offset + src->width / 2;
+ y_center = src->y_offset + src->height / 2;
+
+ /* ensure scaling is between 0.25x .. 16x */
+ src->width = clamp(src->width, round_up(dst->width / 16, 4),
+ dst->width * 4);
+ src->height = clamp(src->height, round_up(dst->height / 16, 4),
+ dst->height * 4);
+
+ /* hardware limits */
+ src->width = clamp(src->width, 32U, 2047U);
+ src->height = clamp(src->height, 4U, 2047U);
+
+ /* setup offsets */
+ src->x_offset = do_center(x_center, src->width,
+ src->full_width, flags);
+ src->y_offset = do_center(y_center, src->height,
+ src->full_height, flags);
+
+ /* setting scaling ratio */
+ geo->x_ratio = (src->width << 16) / dst->width;
+ geo->y_ratio = (src->height << 16) / dst->height;
+ /* fall through */
+
+ case MXR_GEOMETRY_SOURCE:
+ src->full_width = clamp(src->full_width,
+ ALIGN(src->width + src->x_offset, 8), 8192U);
+ src->full_height = clamp(src->full_height,
+ src->height + src->y_offset, 8192U);
+ };
}
/* PUBLIC API */
diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c
index 8cec67ef48c9..f6bca2c20e89 100644
--- a/drivers/media/video/s5p-tv/sdo_drv.c
+++ b/drivers/media/video/s5p-tv/sdo_drv.c
@@ -301,7 +301,7 @@ static int __devinit sdo_probe(struct platform_device *pdev)
struct clk *sclk_vpll;
dev_info(dev, "probe start\n");
- sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+ sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL);
if (!sdev) {
dev_err(dev, "not enough memory.\n");
ret = -ENOMEM;
@@ -314,14 +314,14 @@ static int __devinit sdo_probe(struct platform_device *pdev)
if (res == NULL) {
dev_err(dev, "get memory resource failed.\n");
ret = -ENXIO;
- goto fail_sdev;
+ goto fail;
}
- sdev->regs = ioremap(res->start, resource_size(res));
+ sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (sdev->regs == NULL) {
dev_err(dev, "register mapping failed.\n");
ret = -ENXIO;
- goto fail_sdev;
+ goto fail;
}
/* acquiring interrupt */
@@ -329,12 +329,13 @@ static int __devinit sdo_probe(struct platform_device *pdev)
if (res == NULL) {
dev_err(dev, "get interrupt resource failed.\n");
ret = -ENXIO;
- goto fail_regs;
+ goto fail;
}
- ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev);
+ ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0,
+ "s5p-sdo", sdev);
if (ret) {
dev_err(dev, "request interrupt failed.\n");
- goto fail_regs;
+ goto fail;
}
sdev->irq = res->start;
@@ -343,7 +344,7 @@ static int __devinit sdo_probe(struct platform_device *pdev)
if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
dev_err(dev, "failed to get clock 'sclk_dac'\n");
ret = -ENXIO;
- goto fail_irq;
+ goto fail;
}
sdev->dac = clk_get(dev, "dac");
if (IS_ERR_OR_NULL(sdev->dac)) {
@@ -415,12 +416,6 @@ fail_dac:
clk_put(sdev->dac);
fail_sclk_dac:
clk_put(sdev->sclk_dac);
-fail_irq:
- free_irq(sdev->irq, sdev);
-fail_regs:
- iounmap(sdev->regs);
-fail_sdev:
- kfree(sdev);
fail:
dev_info(dev, "probe failed\n");
return ret;
@@ -439,9 +434,6 @@ static int __devexit sdo_remove(struct platform_device *pdev)
clk_put(sdev->dacphy);
clk_put(sdev->dac);
clk_put(sdev->sclk_dac);
- free_irq(sdev->irq, sdev);
- iounmap(sdev->regs);
- kfree(sdev);
dev_info(&pdev->dev, "remove successful\n");
return 0;
@@ -457,24 +449,4 @@ static struct platform_driver sdo_driver __refdata = {
}
};
-static int __init sdo_init(void)
-{
- int ret;
- static const char banner[] __initdata = KERN_INFO \
- "Samsung Standard Definition Output (SDO) driver, "
- "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
- printk(banner);
-
- ret = platform_driver_register(&sdo_driver);
- if (ret)
- printk(KERN_ERR "SDO platform driver register failed\n");
-
- return ret;
-}
-module_init(sdo_init);
-
-static void __exit sdo_exit(void)
-{
- platform_driver_unregister(&sdo_driver);
-}
-module_exit(sdo_exit);
+module_platform_driver(sdo_driver);
diff --git a/drivers/media/video/s5p-tv/sii9234_drv.c b/drivers/media/video/s5p-tv/sii9234_drv.c
new file mode 100644
index 000000000000..0f31eccd7b80
--- /dev/null
+++ b/drivers/media/video/s5p-tv/sii9234_drv.c
@@ -0,0 +1,432 @@
+/*
+ * Samsung MHL interface driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co.Ltd
+ * Author: Tomasz Stanislawski <t.stanislaws@samsung.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.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/freezer.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/machine.h>
+#include <linux/slab.h>
+
+#include <mach/gpio.h>
+#include <plat/gpio-cfg.h>
+
+#include <media/sii9234.h>
+#include <media/v4l2-subdev.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MHL interface driver");
+MODULE_LICENSE("GPL");
+
+struct sii9234_context {
+ struct i2c_client *client;
+ struct regulator *power;
+ int gpio_n_reset;
+ struct v4l2_subdev sd;
+};
+
+static inline struct sii9234_context *sd_to_context(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct sii9234_context, sd);
+}
+
+static inline int sii9234_readb(struct i2c_client *client, int addr)
+{
+ return i2c_smbus_read_byte_data(client, addr);
+}
+
+static inline int sii9234_writeb(struct i2c_client *client, int addr, int value)
+{
+ return i2c_smbus_write_byte_data(client, addr, value);
+}
+
+static inline int sii9234_writeb_mask(struct i2c_client *client, int addr,
+ int value, int mask)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, addr);
+ if (ret < 0)
+ return ret;
+ ret = (ret & ~mask) | (value & mask);
+ return i2c_smbus_write_byte_data(client, addr, ret);
+}
+
+static inline int sii9234_readb_idx(struct i2c_client *client, int addr)
+{
+ int ret;
+ ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8);
+ if (ret < 0)
+ return ret;
+ ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff);
+ if (ret < 0)
+ return ret;
+ return i2c_smbus_read_byte_data(client, 0xbe);
+}
+
+static inline int sii9234_writeb_idx(struct i2c_client *client, int addr,
+ int value)
+{
+ int ret;
+ ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8);
+ if (ret < 0)
+ return ret;
+ ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff);
+ if (ret < 0)
+ return ret;
+ ret = i2c_smbus_write_byte_data(client, 0xbe, value);
+ return ret;
+}
+
+static inline int sii9234_writeb_idx_mask(struct i2c_client *client, int addr,
+ int value, int mask)
+{
+ int ret;
+
+ ret = sii9234_readb_idx(client, addr);
+ if (ret < 0)
+ return ret;
+ ret = (ret & ~mask) | (value & mask);
+ return sii9234_writeb_idx(client, addr, ret);
+}
+
+static int sii9234_reset(struct sii9234_context *ctx)
+{
+ struct i2c_client *client = ctx->client;
+ struct device *dev = &client->dev;
+ int ret, tries;
+
+ gpio_direction_output(ctx->gpio_n_reset, 1);
+ mdelay(1);
+ gpio_direction_output(ctx->gpio_n_reset, 0);
+ mdelay(1);
+ gpio_direction_output(ctx->gpio_n_reset, 1);
+ mdelay(1);
+
+ /* going to TTPI mode */
+ ret = sii9234_writeb(client, 0xc7, 0);
+ if (ret < 0) {
+ dev_err(dev, "failed to set TTPI mode\n");
+ return ret;
+ }
+ for (tries = 0; tries < 100 ; ++tries) {
+ ret = sii9234_readb(client, 0x1b);
+ if (ret > 0)
+ break;
+ if (ret < 0) {
+ dev_err(dev, "failed to reset device\n");
+ return -EIO;
+ }
+ mdelay(1);
+ }
+ if (tries == 100) {
+ dev_err(dev, "maximal number of tries reached\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int sii9234_verify_version(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ int family, rev, tpi_rev, dev_id, sub_id, hdcp, id;
+
+ family = sii9234_readb(client, 0x1b);
+ rev = sii9234_readb(client, 0x1c) & 0x0f;
+ tpi_rev = sii9234_readb(client, 0x1d) & 0x7f;
+ dev_id = sii9234_readb_idx(client, 0x0103);
+ sub_id = sii9234_readb_idx(client, 0x0102);
+ hdcp = sii9234_readb(client, 0x30);
+
+ if (family < 0 || rev < 0 || tpi_rev < 0 || dev_id < 0 ||
+ sub_id < 0 || hdcp < 0) {
+ dev_err(dev, "failed to read chip's version\n");
+ return -EIO;
+ }
+
+ id = (dev_id << 8) | sub_id;
+
+ dev_info(dev, "chip: SiL%02x family: %02x, rev: %02x\n",
+ id, family, rev);
+ dev_info(dev, "tpi_rev:%02x, hdcp: %02x\n", tpi_rev, hdcp);
+ if (id != 0x9234) {
+ dev_err(dev, "not supported chip\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static u8 data[][3] = {
+/* setup from driver created by doonsoo45.kim */
+ { 0x01, 0x05, 0x04 }, /* Enable Auto soft reset on SCDT = 0 */
+ { 0x01, 0x08, 0x35 }, /* Power Up TMDS Tx Core */
+ { 0x01, 0x0d, 0x1c }, /* HDMI Transcode mode enable */
+ { 0x01, 0x2b, 0x01 }, /* Enable HDCP Compliance workaround */
+ { 0x01, 0x79, 0x40 }, /* daniel test...MHL_INT */
+ { 0x01, 0x80, 0x34 }, /* Enable Rx PLL Clock Value */
+ { 0x01, 0x90, 0x27 }, /* Enable CBUS discovery */
+ { 0x01, 0x91, 0xe5 }, /* Skip RGND detection */
+ { 0x01, 0x92, 0x46 }, /* Force MHD mode */
+ { 0x01, 0x93, 0xdc }, /* Disable CBUS pull-up during RGND measurement */
+ { 0x01, 0x94, 0x66 }, /* 1.8V CBUS VTH & GND threshold */
+ { 0x01, 0x95, 0x31 }, /* RGND block & single discovery attempt */
+ { 0x01, 0x96, 0x22 }, /* use 1K and 2K setting */
+ { 0x01, 0xa0, 0x10 }, /* SIMG: Term mode */
+ { 0x01, 0xa1, 0xfc }, /* Disable internal Mobile HD driver */
+ { 0x01, 0xa3, 0xfa }, /* SIMG: Output Swing default EB, 3x Clk Mult */
+ { 0x01, 0xa5, 0x80 }, /* SIMG: RGND Hysterisis, 3x mode for Beast */
+ { 0x01, 0xa6, 0x0c }, /* SIMG: Swing Offset */
+ { 0x02, 0x3d, 0x3f }, /* Power up CVCC 1.2V core */
+ { 0x03, 0x00, 0x00 }, /* SIMG: correcting HW default */
+ { 0x03, 0x11, 0x01 }, /* Enable TxPLL Clock */
+ { 0x03, 0x12, 0x15 }, /* Enable Tx Clock Path & Equalizer */
+ { 0x03, 0x13, 0x60 }, /* SIMG: Set termination value */
+ { 0x03, 0x14, 0xf0 }, /* SIMG: Change CKDT level */
+ { 0x03, 0x17, 0x07 }, /* SIMG: PLL Calrefsel */
+ { 0x03, 0x1a, 0x20 }, /* VCO Cal */
+ { 0x03, 0x22, 0xe0 }, /* SIMG: Auto EQ */
+ { 0x03, 0x23, 0xc0 }, /* SIMG: Auto EQ */
+ { 0x03, 0x24, 0xa0 }, /* SIMG: Auto EQ */
+ { 0x03, 0x25, 0x80 }, /* SIMG: Auto EQ */
+ { 0x03, 0x26, 0x60 }, /* SIMG: Auto EQ */
+ { 0x03, 0x27, 0x40 }, /* SIMG: Auto EQ */
+ { 0x03, 0x28, 0x20 }, /* SIMG: Auto EQ */
+ { 0x03, 0x29, 0x00 }, /* SIMG: Auto EQ */
+ { 0x03, 0x31, 0x0b }, /* SIMG: Rx PLL BW value from I2C BW ~ 4MHz */
+ { 0x03, 0x45, 0x06 }, /* SIMG: DPLL Mode */
+ { 0x03, 0x4b, 0x06 }, /* SIMG: Correcting HW default */
+ { 0x03, 0x4c, 0xa0 }, /* Manual zone control */
+ { 0x03, 0x4d, 0x02 }, /* SIMG: PLL Mode Value (order is important) */
+};
+
+static int sii9234_set_internal(struct sii9234_context *ctx)
+{
+ struct i2c_client *client = ctx->client;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(data); ++i) {
+ int addr = (data[i][0] << 8) | data[i][1];
+ ret = sii9234_writeb_idx(client, addr, data[i][2]);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int sii9234_runtime_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct sii9234_context *ctx = sd_to_context(sd);
+ struct i2c_client *client = ctx->client;
+
+ dev_info(dev, "suspend start\n");
+
+ sii9234_writeb_mask(client, 0x1e, 3, 3);
+ regulator_disable(ctx->power);
+
+ return 0;
+}
+
+static int sii9234_runtime_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct sii9234_context *ctx = sd_to_context(sd);
+ struct i2c_client *client = ctx->client;
+ int ret;
+
+ dev_info(dev, "resume start\n");
+ regulator_enable(ctx->power);
+
+ ret = sii9234_reset(ctx);
+ if (ret)
+ goto fail;
+
+ /* enable tpi */
+ ret = sii9234_writeb_mask(client, 0x1e, 1, 0);
+ if (ret < 0)
+ goto fail;
+ ret = sii9234_set_internal(ctx);
+ if (ret < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ dev_err(dev, "failed to resume\n");
+ regulator_disable(ctx->power);
+
+ return ret;
+}
+
+static const struct dev_pm_ops sii9234_pm_ops = {
+ .runtime_suspend = sii9234_runtime_suspend,
+ .runtime_resume = sii9234_runtime_resume,
+};
+
+static int sii9234_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct sii9234_context *ctx = sd_to_context(sd);
+ int ret;
+
+ if (on)
+ ret = pm_runtime_get_sync(&ctx->client->dev);
+ else
+ ret = pm_runtime_put(&ctx->client->dev);
+ /* only values < 0 indicate errors */
+ return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sii9234_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct sii9234_context *ctx = sd_to_context(sd);
+
+ /* (dis/en)able TDMS output */
+ sii9234_writeb_mask(ctx->client, 0x1a, enable ? 0 : ~0 , 1 << 4);
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops sii9234_core_ops = {
+ .s_power = sii9234_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sii9234_video_ops = {
+ .s_stream = sii9234_s_stream,
+};
+
+static const struct v4l2_subdev_ops sii9234_ops = {
+ .core = &sii9234_core_ops,
+ .video = &sii9234_video_ops,
+};
+
+static int __devinit sii9234_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct sii9234_platform_data *pdata = dev->platform_data;
+ struct sii9234_context *ctx;
+ int ret;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ dev_err(dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+ ctx->client = client;
+
+ ctx->power = regulator_get(dev, "hdmi-en");
+ if (IS_ERR(ctx->power)) {
+ dev_err(dev, "failed to acquire regulator hdmi-en\n");
+ ret = PTR_ERR(ctx->power);
+ goto fail_ctx;
+ }
+
+ ctx->gpio_n_reset = pdata->gpio_n_reset;
+ ret = gpio_request(ctx->gpio_n_reset, "MHL_RST");
+ if (ret) {
+ dev_err(dev, "failed to acquire MHL_RST gpio\n");
+ goto fail_power;
+ }
+
+ v4l2_i2c_subdev_init(&ctx->sd, client, &sii9234_ops);
+
+ pm_runtime_enable(dev);
+
+ /* enable device */
+ ret = pm_runtime_get_sync(dev);
+ if (ret)
+ goto fail_pm;
+
+ /* verify chip version */
+ ret = sii9234_verify_version(client);
+ if (ret)
+ goto fail_pm_get;
+
+ /* stop processing */
+ pm_runtime_put(dev);
+
+ dev_info(dev, "probe successful\n");
+
+ return 0;
+
+fail_pm_get:
+ pm_runtime_put_sync(dev);
+
+fail_pm:
+ pm_runtime_disable(dev);
+ gpio_free(ctx->gpio_n_reset);
+
+fail_power:
+ regulator_put(ctx->power);
+
+fail_ctx:
+ kfree(ctx);
+
+fail:
+ dev_err(dev, "probe failed\n");
+
+ return ret;
+}
+
+static int __devexit sii9234_remove(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct sii9234_context *ctx = sd_to_context(sd);
+
+ pm_runtime_disable(dev);
+ gpio_free(ctx->gpio_n_reset);
+ regulator_put(ctx->power);
+ kfree(ctx);
+
+ dev_info(dev, "remove successful\n");
+
+ return 0;
+}
+
+
+static const struct i2c_device_id sii9234_id[] = {
+ { "SII9234", 0 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, sii9234_id);
+static struct i2c_driver sii9234_driver = {
+ .driver = {
+ .name = "sii9234",
+ .owner = THIS_MODULE,
+ .pm = &sii9234_pm_ops,
+ },
+ .probe = sii9234_probe,
+ .remove = __devexit_p(sii9234_remove),
+ .id_table = sii9234_id,
+};
+
+static int __init sii9234_init(void)
+{
+ return i2c_add_driver(&sii9234_driver);
+}
+module_init(sii9234_init);
+
+static void __exit sii9234_exit(void)
+{
+ i2c_del_driver(&sii9234_driver);
+}
+module_exit(sii9234_exit);
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 99a2ac16f9e5..0caac50d7cf4 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -539,15 +539,4 @@ static struct i2c_driver saa6588_driver = {
.id_table = saa6588_id,
};
-static __init int init_saa6588(void)
-{
- return i2c_add_driver(&saa6588_driver);
-}
-
-static __exit void exit_saa6588(void)
-{
- i2c_del_driver(&saa6588_driver);
-}
-
-module_init(init_saa6588);
-module_exit(exit_saa6588);
+module_i2c_driver(saa6588_driver);
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 99664205ef4e..51cd4c8f0520 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -491,15 +491,4 @@ static struct i2c_driver saa7110_driver = {
.id_table = saa7110_id,
};
-static __init int init_saa7110(void)
-{
- return i2c_add_driver(&saa7110_driver);
-}
-
-static __exit void exit_saa7110(void)
-{
- i2c_del_driver(&saa7110_driver);
-}
-
-module_init(init_saa7110);
-module_exit(exit_saa7110);
+module_i2c_driver(saa7110_driver);
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 5cfdbc78b918..2107336cd836 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -57,7 +57,7 @@ MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
"Hans Verkuil, Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
-static int debug;
+static bool debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -1724,15 +1724,4 @@ static struct i2c_driver saa711x_driver = {
.id_table = saa711x_id,
};
-static __init int init_saa711x(void)
-{
- return i2c_add_driver(&saa711x_driver);
-}
-
-static __exit void exit_saa711x(void)
-{
- i2c_del_driver(&saa711x_driver);
-}
-
-module_init(init_saa711x);
-module_exit(exit_saa711x);
+module_i2c_driver(saa711x_driver);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index ad964616c9d2..39c90b08eea8 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -852,15 +852,4 @@ static struct i2c_driver saa7127_driver = {
.id_table = saa7127_id,
};
-static __init int init_saa7127(void)
-{
- return i2c_add_driver(&saa7127_driver);
-}
-
-static __exit void exit_saa7127(void)
-{
- i2c_del_driver(&saa7127_driver);
-}
-
-module_init(init_saa7127);
-module_exit(exit_saa7127);
+module_i2c_driver(saa7127_driver);
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index a646ccf51696..da3899329f52 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/video
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index f9f29cc93a8a..f147b05bd860 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -1001,18 +1001,7 @@ static struct i2c_driver saa6752hs_driver = {
.id_table = saa6752hs_id,
};
-static __init int init_saa6752hs(void)
-{
- return i2c_add_driver(&saa6752hs_driver);
-}
-
-static __exit void exit_saa6752hs(void)
-{
- i2c_del_driver(&saa6752hs_driver);
-}
-
-module_init(init_saa6752hs);
-module_exit(exit_saa6752hs);
+module_i2c_driver(saa6752hs_driver);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 0f9fb99adeb4..53aae5968ffb 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -33,6 +33,7 @@
#include "tea5767.h"
#include "tda18271.h"
#include "xc5000.h"
+#include "s5h1411.h"
/* commly used strings */
static char name_mute[] = "mute";
@@ -5691,6 +5692,57 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
},
},
+ [SAA7134_BOARD_SENSORAY811_911] = {
+ .name = "Sensoray 811/911",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .name = name_comp3,
+ .vmux = 2,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ },
+ [SAA7134_BOARD_KWORLD_PC150U] = {
+ .name = "Kworld PC150-U",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 1 << 21,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0000000,
+ },
+ },
};
@@ -6285,6 +6337,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+ .subvendor = 0x17de,
+ .subdevice = 0xa134,
+ .driver_data = SAA7134_BOARD_KWORLD_PC150U,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x1461,
.subdevice = 0x7360,
@@ -6914,6 +6972,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0xd136,
.driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x6000,
+ .subdevice = 0x0811,
+ .driver_data = SAA7134_BOARD_SENSORAY811_911,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x6000,
+ .subdevice = 0x0911,
+ .driver_data = SAA7134_BOARD_SENSORAY811_911,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -7101,6 +7171,23 @@ static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev,
return 0;
}
+static int saa7134_kworld_pc150u_toggle_agc(struct saa7134_dev *dev,
+ enum tda18271_mode mode)
+{
+ switch (mode) {
+ case TDA18271_ANALOG:
+ saa7134_set_gpio(dev, 18, 0);
+ break;
+ case TDA18271_DIGITAL:
+ saa7134_set_gpio(dev, 18, 1);
+ msleep(30);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
int command, int arg)
{
@@ -7117,6 +7204,9 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg);
break;
+ case SAA7134_BOARD_KWORLD_PC150U:
+ ret = saa7134_kworld_pc150u_toggle_agc(dev, arg);
+ break;
default:
break;
}
@@ -7138,6 +7228,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
case SAA7134_BOARD_AVERMEDIA_M733A:
case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ case SAA7134_BOARD_KWORLD_PC150U:
case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
/* tda8290 + tda18271 */
ret = saa7134_tda8290_18271_callback(dev, command, arg);
@@ -7419,6 +7510,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_X7:
case SAA7134_BOARD_BEHOLD_H7:
case SAA7134_BOARD_BEHOLD_A7:
+ case SAA7134_BOARD_KWORLD_PC150U:
dev->has_remote = SAA7134_REMOTE_I2C;
break;
case SAA7134_BOARD_AVERMEDIA_A169_B:
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index ca65cda3e101..5fbb4e49495c 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -1263,7 +1263,6 @@ static int saa7134_resume(struct pci_dev *pci_dev)
saa7134_tvaudio_setmute(dev);
saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
saa7134_tvaudio_init(dev);
- saa7134_tvaudio_do_scan(dev);
saa7134_enable_i2s(dev);
saa7134_hw_enable2(dev);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 1e4ef1669887..aaa5c97a7216 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -61,6 +61,7 @@
#include "zl10036.h"
#include "zl10039.h"
#include "mt312.h"
+#include "s5h1411.h"
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -183,9 +184,9 @@ static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe)
return 0;
}
-static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int mt352_pinnacle_tuner_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u8 off[] = { 0x00, 0xf1};
u8 on[] = { 0x00, 0x71};
struct i2c_msg msg = {.addr=0x43, .flags=0, .buf=off, .len = sizeof(off)};
@@ -196,7 +197,7 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
/* set frequency (mt2050) */
f.tuner = 0;
f.type = V4L2_TUNER_DIGITAL_TV;
- f.frequency = params->frequency / 1000 * 16 / 1000;
+ f.frequency = c->frequency / 1000 * 16 / 1000;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
@@ -287,8 +288,9 @@ static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
* these tuners are tu1216, td1316(a)
*/
-static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda6651_pll_set(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct saa7134_dev *dev = fe->dvb->priv;
struct tda1004x_state *state = fe->demodulator_priv;
u8 addr = state->config->tuner_address;
@@ -299,7 +301,7 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
u8 band, cp, filter;
/* determine charge pump */
- tuner_frequency = params->frequency + 36166000;
+ tuner_frequency = c->frequency + 36166000;
if (tuner_frequency < 87000000)
return -EINVAL;
else if (tuner_frequency < 130000000)
@@ -324,28 +326,28 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
return -EINVAL;
/* determine band */
- if (params->frequency < 49000000)
+ if (c->frequency < 49000000)
return -EINVAL;
- else if (params->frequency < 161000000)
+ else if (c->frequency < 161000000)
band = 1;
- else if (params->frequency < 444000000)
+ else if (c->frequency < 444000000)
band = 2;
- else if (params->frequency < 861000000)
+ else if (c->frequency < 861000000)
band = 4;
else
return -EINVAL;
/* setup PLL filter */
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
+ switch (c->bandwidth_hz) {
+ case 6000000:
filter = 0;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000000:
filter = 0;
break;
- case BANDWIDTH_8_MHZ:
+ case 8000000:
filter = 1;
break;
@@ -356,7 +358,7 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
/* calculate divisor
* ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
*/
- tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000;
+ tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000;
/* setup tuner buffer */
tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
@@ -436,9 +438,9 @@ static int philips_td1316_tuner_init(struct dvb_frontend *fe)
return 0;
}
-static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_td1316_tuner_set_params(struct dvb_frontend *fe)
{
- return philips_tda6651_pll_set(fe, params);
+ return philips_tda6651_pll_set(fe);
}
static int philips_td1316_tuner_sleep(struct dvb_frontend *fe)
@@ -1157,6 +1159,33 @@ static struct tda18271_config prohdtv_pro2_tda18271_config = {
.output_opt = TDA18271_OUTPUT_LT_OFF,
};
+static struct tda18271_std_map kworld_tda18271_std_map = {
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 3,
+ .if_lvl = 6, .rfagc_top = 0x37 },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+ .if_lvl = 6, .rfagc_top = 0x37 },
+};
+
+static struct tda18271_config kworld_pc150u_tda18271_config = {
+ .std_map = &kworld_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+ .config = 3, /* Use tuner callback for AGC */
+ .rf_cal_on_startup = 1
+};
+
+static struct s5h1411_config kworld_s5h1411_config = {
+ .output_mode = S5H1411_PARALLEL_OUTPUT,
+ .gpio = S5H1411_GPIO_OFF,
+ .qam_if = S5H1411_IF_4000,
+ .vsb_if = S5H1411_IF_3250,
+ .inversion = S5H1411_INVERSION_ON,
+ .status_mode = S5H1411_DEMODLOCKING,
+ .mpeg_timing =
+ S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+
/* ==================================================================
* Core code
*/
@@ -1437,6 +1466,22 @@ static int dvb_init(struct saa7134_dev *dev)
&dev->i2c_adap, 0x61,
TUNER_PHILIPS_TUV1236D);
break;
+ case SAA7134_BOARD_KWORLD_PC150U:
+ saa7134_set_gpio(dev, 18, 1); /* Switch to digital mode */
+ saa7134_tuner_callback(dev, 0,
+ TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+ &kworld_s5h1411_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &kworld_pc150u_tda18271_config);
+ }
+ break;
case SAA7134_BOARD_FLYDVBS_LR300:
fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
&dev->i2c_adap);
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 2d3f6d265bbf..a176ec3285e0 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -254,7 +254,9 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
addr = msgs[i].addr << 1;
if (msgs[i].flags & I2C_M_RD)
addr |= 1;
- if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) {
+ if (i > 0 && msgs[i].flags &
+ I2C_M_RD && msgs[i].addr != 0x40 &&
+ msgs[i].addr != 0x19) {
/* workaround for a saa7134 i2c bug
* needed to talk to the mt352 demux
* thanks to pinnacle for the hint */
@@ -279,6 +281,16 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
d1printk("%02x", rc);
msgs[i].buf[byte] = rc;
}
+ /* discard mysterious extra byte when reading
+ from Samsung S5H1411. i2c bus gets error
+ if we do not. */
+ if (0x19 == msgs[i].addr) {
+ d1printk(" ?");
+ rc = i2c_recv_byte(dev);
+ if (rc < 0)
+ goto err;
+ d1printk("%02x", rc);
+ }
} else {
/* write bytes */
d2printk("write bytes\n");
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index d4ee24bf6928..48d2878699b7 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -210,6 +210,54 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
return 1;
}
+/* copied and modified from get_key_msi_tvanywhere_plus() */
+static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key,
+ u32 *ir_raw)
+{
+ unsigned char b;
+ unsigned int gpio;
+
+ /* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+ struct saa7134_dev *dev = ir->c->adapter->algo_data;
+ if (dev == NULL) {
+ i2cdprintk("get_key_kworld_pc150u: "
+ "ir->c->adapter->algo_data is NULL!\n");
+ return -EIO;
+ }
+
+ /* rising SAA7134_GPIO_GPRESCAN reads the status */
+
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+ gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+ /* GPIO&0x100 is pulsed low when a button is pressed. Don't do
+ I2C receive if gpio&0x100 is not low. */
+
+ if (gpio & 0x100)
+ return 0; /* No button press */
+
+ /* GPIO says there is a button press. Get it. */
+
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ i2cdprintk("read error\n");
+ return -EIO;
+ }
+
+ /* No button press */
+
+ if (b == 0xff)
+ return 0;
+
+ /* Button pressed */
+
+ dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b);
+ *ir_key = b;
+ *ir_raw = b;
+ return 1;
+}
+
static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char b;
@@ -235,22 +283,25 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
- unsigned char buf[5], cod4, code3, code4;
+ unsigned char buf[5];
/* poll IR chip */
if (5 != i2c_master_recv(ir->c, buf, 5))
return -EIO;
- cod4 = buf[4];
- code4 = (cod4 >> 2);
- code3 = buf[3];
- if (code3 == 0)
- /* no key pressed */
+ /* Check if some key were pressed */
+ if (!(buf[0] & 0x80))
return 0;
- /* return key */
- *ir_key = code4;
- *ir_raw = code4;
+ /*
+ * buf[3] & 0x80 is always high.
+ * buf[3] & 0x40 is a parity bit. A repeat event is marked
+ * by preserving it into two separate readings
+ * buf[4] bits 0 and 1, and buf[1] and buf[2] are always
+ * zero.
+ */
+ *ir_key = 0x1fff & ((buf[3] << 8) | (buf[4] >> 2));
+ *ir_raw = *ir_key;
return 1;
}
@@ -752,7 +803,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
polling = 50; /* ms */
break;
case SAA7134_BOARD_VIDEOMATE_M1F:
- ir_codes = RC_MAP_VIDEOMATE_M1F;
+ ir_codes = RC_MAP_VIDEOMATE_K100;
mask_keycode = 0x0ff00;
mask_keyup = 0x040000;
break;
@@ -898,6 +949,21 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
msg_msi.addr, dev->i2c_adap.name,
(1 == rc) ? "yes" : "no");
break;
+ case SAA7134_BOARD_KWORLD_PC150U:
+ /* copied and modified from MSI TV@nywhere Plus */
+ dev->init_data.name = "Kworld PC150-U";
+ dev->init_data.get_key = get_key_kworld_pc150u;
+ dev->init_data.ir_codes = RC_MAP_KWORLD_PC150U;
+ info.addr = 0x30;
+ /* MSI TV@nywhere Plus controller doesn't seem to
+ respond to probes unless we read something from
+ an existing device. Weird...
+ REVISIT: might no longer be needed */
+ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+ dprintk("probe 0x%02x @ %s: %s\n",
+ msg_msi.addr, dev->i2c_adap.name,
+ (1 == rc) ? "yes" : "no");
+ break;
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
dev->init_data.name = "HVR 1110";
dev->init_data.get_key = get_key_hvr1110;
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 57e646bb48b3..b7a99bee2f98 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -332,6 +332,13 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan)
{
__s32 left,right,value;
+ if (!(dev->tvnorm->id & scan->std)) {
+ value = 0;
+ dprintk("skipping %d.%03d MHz [%4s]\n",
+ scan->carr / 1000, scan->carr % 1000, scan->name);
+ return 0;
+ }
+
if (audio_debug > 1) {
int i;
dprintk("debug %d:",scan->carr);
@@ -348,30 +355,25 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan)
}
printk("\n");
}
- if (dev->tvnorm->id & scan->std) {
- tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90);
- saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
- if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
- return -1;
- left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
-
- tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90);
- saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
- if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
- return -1;
- right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
-
- left >>= 16;
- right >>= 16;
- value = left > right ? left - right : right - left;
- dprintk("scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n",
- scan->carr / 1000, scan->carr % 1000,
- scan->name, value, left, right);
- } else {
- value = 0;
- dprintk("skipping %d.%03d MHz [%4s]\n",
- scan->carr / 1000, scan->carr % 1000, scan->name);
- }
+
+ tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90);
+ saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+ if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+ return -1;
+ left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+ tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90);
+ saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+ if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+ return -1;
+ right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+ left >>= 16;
+ right >>= 16;
+ value = left > right ? left - right : right - left;
+ dprintk("scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n",
+ scan->carr / 1000, scan->carr % 1000,
+ scan->name, value, left, right);
return value;
}
@@ -546,6 +548,7 @@ static int tvaudio_thread(void *data)
dev->tvnorm->name, carrier/1000, carrier%1000,
max1, max2);
dev->last_carrier = carrier;
+ dev->automute = 0;
} else if (0 != dev->last_carrier) {
/* no carrier -- try last detected one as fallback */
@@ -553,6 +556,7 @@ static int tvaudio_thread(void *data)
dprintk("audio carrier scan failed, "
"using %d.%03d MHz [last detected]\n",
carrier/1000, carrier%1000);
+ dev->automute = 1;
} else {
/* no carrier + no fallback -- use default */
@@ -560,9 +564,9 @@ static int tvaudio_thread(void *data)
dprintk("audio carrier scan failed, "
"using %d.%03d MHz [default]\n",
carrier/1000, carrier%1000);
+ dev->automute = 1;
}
tvaudio_setcarrier(dev,carrier,carrier);
- dev->automute = 0;
saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00);
saa7134_tvaudio_setmute(dev);
/* find the exact tv audio norm */
@@ -601,7 +605,7 @@ static int tvaudio_thread(void *data)
if (kthread_should_stop())
break;
if (UNSET == dev->thread.mode) {
- rx = tvaudio_getstereo(dev,&tvaudio[i]);
+ rx = tvaudio_getstereo(dev, &tvaudio[audio]);
mode = saa7134_tvaudio_rx2mode(rx);
} else {
mode = dev->thread.mode;
@@ -1020,6 +1024,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
}
dev->thread.thread = NULL;
+ dev->thread.scan1 = dev->thread.scan2 = 0;
if (my_thread) {
saa7134_tvaudio_init(dev);
/* start tvaudio thread */
@@ -1029,13 +1034,19 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
dev->name);
/* XXX: missing error handling here */
}
- saa7134_tvaudio_do_scan(dev);
}
saa7134_enable_i2s(dev);
return 0;
}
+int saa7134_tvaudio_close(struct saa7134_dev *dev)
+{
+ dev->automute = 1;
+ /* anything else to undo? */
+ return 0;
+}
+
int saa7134_tvaudio_fini(struct saa7134_dev *dev)
{
/* shutdown tvaudio thread */
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 9cf7914f6f90..417034eb6ad2 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1462,6 +1462,8 @@ static int video_release(struct file *file)
struct saa6588_command cmd;
unsigned long flags;
+ saa7134_tvaudio_close(dev);
+
/* turn off overlay */
if (res_check(fh, RESOURCE_OVERLAY)) {
spin_lock_irqsave(&dev->slock,flags);
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 9b550687213a..f625060e6a0f 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -126,8 +126,8 @@ struct saa7134_card_ir {
unsigned users;
u32 polling;
- u32 last_gpio;
- u32 mask_keycode, mask_keydown, mask_keyup;
+ u32 last_gpio;
+ u32 mask_keycode, mask_keydown, mask_keyup;
bool running;
bool active;
@@ -330,6 +330,8 @@ struct saa7134_card_ir {
#define SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2 185
#define SAA7134_BOARD_BEHOLD_501 186
#define SAA7134_BOARD_BEHOLD_503FM 187
+#define SAA7134_BOARD_SENSORAY811_911 188
+#define SAA7134_BOARD_KWORLD_PC150U 189
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
@@ -817,6 +819,7 @@ void saa7134_tvaudio_init(struct saa7134_dev *dev);
int saa7134_tvaudio_init2(struct saa7134_dev *dev);
int saa7134_tvaudio_fini(struct saa7134_dev *dev);
int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
+int saa7134_tvaudio_close(struct saa7134_dev *dev);
int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);
diff --git a/drivers/media/video/saa7164/Makefile b/drivers/media/video/saa7164/Makefile
index ecd5811dc486..068443af30c8 100644
--- a/drivers/media/video/saa7164/Makefile
+++ b/drivers/media/video/saa7164/Makefile
@@ -4,9 +4,9 @@ saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \
obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/video
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/video/saa7164/saa7164-bus.c
index 466e1b02f91f..a7f58a998752 100644
--- a/drivers/media/video/saa7164/saa7164-bus.c
+++ b/drivers/media/video/saa7164/saa7164-bus.c
@@ -149,7 +149,7 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
saa7164_bus_verify(dev);
msg->size = cpu_to_le16(msg->size);
- msg->command = cpu_to_le16(msg->command);
+ msg->command = cpu_to_le32(msg->command);
msg->controlselector = cpu_to_le16(msg->controlselector);
if (msg->size > dev->bus.m_wMaxReqSize) {
@@ -464,7 +464,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
peekout:
msg->size = le16_to_cpu(msg->size);
- msg->command = le16_to_cpu(msg->command);
+ msg->command = le32_to_cpu(msg->command);
msg->controlselector = le16_to_cpu(msg->controlselector);
ret = SAA_OK;
out:
diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c
index 971591d6450f..5b72da5ce418 100644
--- a/drivers/media/video/saa7164/saa7164-cards.c
+++ b/drivers/media/video/saa7164/saa7164-cards.c
@@ -269,8 +269,6 @@ struct saa7164_board saa7164_boards[] = {
.portb = SAA7164_MPEG_DVB,
.portc = SAA7164_MPEG_ENCODER,
.portd = SAA7164_MPEG_ENCODER,
- .portc = SAA7164_MPEG_ENCODER,
- .portd = SAA7164_MPEG_ENCODER,
.porte = SAA7164_MPEG_VBI,
.portf = SAA7164_MPEG_VBI,
.chiprev = SAA7164_CHIP_REV3,
@@ -333,8 +331,6 @@ struct saa7164_board saa7164_boards[] = {
.portd = SAA7164_MPEG_ENCODER,
.porte = SAA7164_MPEG_VBI,
.portf = SAA7164_MPEG_VBI,
- .porte = SAA7164_MPEG_VBI,
- .portf = SAA7164_MPEG_VBI,
.chiprev = SAA7164_CHIP_REV3,
.unit = {{
.id = 0x28,
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c
index 2fd38a01887f..a9ed686ad08a 100644
--- a/drivers/media/video/saa7164/saa7164-encoder.c
+++ b/drivers/media/video/saa7164/saa7164-encoder.c
@@ -791,11 +791,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_log_status(struct file *file, void *priv)
-{
- return 0;
-}
-
static int fill_queryctrl(struct saa7164_encoder_params *params,
struct v4l2_queryctrl *c)
{
@@ -1347,7 +1342,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
.vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
.vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
- .vidioc_log_status = vidioc_log_status,
.vidioc_queryctrl = vidioc_queryctrl,
.vidioc_g_chip_ident = saa7164_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c
index e2e034158718..273cf807401c 100644
--- a/drivers/media/video/saa7164/saa7164-vbi.c
+++ b/drivers/media/video/saa7164/saa7164-vbi.c
@@ -730,11 +730,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_log_status(struct file *file, void *priv)
-{
- return 0;
-}
-
static int fill_queryctrl(struct saa7164_vbi_params *params,
struct v4l2_queryctrl *c)
{
@@ -1256,7 +1251,6 @@ static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
.vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
.vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
.vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
- .vidioc_log_status = vidioc_log_status,
.vidioc_queryctrl = vidioc_queryctrl,
#if 0
.vidioc_g_chip_ident = saa7164_g_chip_ident,
diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c
index b6172c2c517e..1e84466515aa 100644
--- a/drivers/media/video/saa717x.c
+++ b/drivers/media/video/saa717x.c
@@ -1375,15 +1375,4 @@ static struct i2c_driver saa717x_driver = {
.id_table = saa717x_id,
};
-static __init int init_saa717x(void)
-{
- return i2c_add_driver(&saa717x_driver);
-}
-
-static __exit void exit_saa717x(void)
-{
- i2c_del_driver(&saa717x_driver);
-}
-
-module_init(init_saa717x);
-module_exit(exit_saa717x);
+module_i2c_driver(saa717x_driver);
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 96f56c2f11f3..2c6b65c76e2b 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -374,15 +374,4 @@ static struct i2c_driver saa7185_driver = {
.id_table = saa7185_id,
};
-static __init int init_saa7185(void)
-{
- return i2c_add_driver(&saa7185_driver);
-}
-
-static __exit void exit_saa7185(void)
-{
- i2c_del_driver(&saa7185_driver);
-}
-
-module_init(init_saa7185);
-module_exit(exit_saa7185);
+module_i2c_driver(saa7185_driver);
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
index 211fa25a1239..d7d1670e0ca3 100644
--- a/drivers/media/video/saa7191.c
+++ b/drivers/media/video/saa7191.c
@@ -656,15 +656,4 @@ static struct i2c_driver saa7191_driver = {
.id_table = saa7191_id,
};
-static __init int init_saa7191(void)
-{
- return i2c_add_driver(&saa7191_driver);
-}
-
-static __exit void exit_saa7191(void)
-{
- i2c_del_driver(&saa7191_driver);
-}
-
-module_init(init_saa7191);
-module_exit(exit_saa7191);
+module_i2c_driver(saa7191_driver);
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index c51decfcae19..424dfacd263a 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -112,6 +112,10 @@ struct sh_mobile_ceu_dev {
u32 cflcr;
+ /* static max sizes either from platform data or default */
+ int max_width;
+ int max_height;
+
enum v4l2_field field;
int sequence;
@@ -786,8 +790,7 @@ static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev,
V4L2_MBUS_DATA_ACTIVE_HIGH)
/* Capture is not running, no interrupts, no locking needed */
-static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
- __u32 pixfmt)
+static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
@@ -925,11 +928,6 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
ceu_write(pcdev, CDOCR, value);
ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
- dev_dbg(icd->parent, "S_FMT successful for %c%c%c%c %ux%u\n",
- pixfmt & 0xff, (pixfmt >> 8) & 0xff,
- (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
- icd->user_width, icd->user_height);
-
capture_restore(pcdev, capsr);
/* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */
@@ -1087,7 +1085,15 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
if (ret < 0)
return ret;
- while ((mf.width > 2560 || mf.height > 1920) && shift < 4) {
+ /*
+ * All currently existing CEU implementations support 2560x1920
+ * or larger frames. If the sensor is proposing too big a frame,
+ * don't bother with possibly supportred by the CEU larger
+ * sizes, just try VGA multiples. If needed, this can be
+ * adjusted in the future.
+ */
+ while ((mf.width > pcdev->max_width ||
+ mf.height > pcdev->max_height) && shift < 4) {
/* Try 2560x1920, 1280x960, 640x480, 320x240 */
mf.width = 2560 >> shift;
mf.height = 1920 >> shift;
@@ -1383,6 +1389,8 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
static int client_s_fmt(struct soc_camera_device *icd,
struct v4l2_mbus_framefmt *mf, bool ceu_can_scale)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
struct sh_mobile_ceu_cam *cam = icd->host_priv;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->parent;
@@ -1416,8 +1424,8 @@ static int client_s_fmt(struct soc_camera_device *icd,
if (ret < 0)
return ret;
- max_width = min(cap.bounds.width, 2560);
- max_height = min(cap.bounds.height, 1920);
+ max_width = min(cap.bounds.width, pcdev->max_width);
+ max_height = min(cap.bounds.height, pcdev->max_height);
/* Camera set a format, but geometry is not precise, try to improve */
tmp_w = mf->width;
@@ -1557,7 +1565,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
if (ret < 0)
return ret;
- if (mf.width > 2560 || mf.height > 1920)
+ if (mf.width > pcdev->max_width || mf.height > pcdev->max_height)
return -EINVAL;
/* 4. Calculate camera scales */
@@ -1840,6 +1848,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -1860,8 +1870,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
/* FIXME: calculate using depth and bus width */
/* CFSZR requires height and width to be 4-pixel aligned */
- v4l_bound_align_image(&pix->width, 2, 2560, 2,
- &pix->height, 4, 1920, 2, 0);
+ v4l_bound_align_image(&pix->width, 2, pcdev->max_width, 2,
+ &pix->height, 4, pcdev->max_height, 2, 0);
width = pix->width;
height = pix->height;
@@ -1896,8 +1906,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
* requested a bigger rectangle, it will not return a
* smaller one.
*/
- mf.width = 2560;
- mf.height = 1920;
+ mf.width = pcdev->max_width;
+ mf.height = pcdev->max_height;
ret = v4l2_device_call_until_err(sd->v4l2_dev,
soc_camera_grp_id(icd), video,
try_mbus_fmt, &mf);
@@ -1966,8 +1976,7 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
if (!ret) {
icd->user_width = out_width & ~3;
icd->user_height = out_height & ~3;
- ret = sh_mobile_ceu_set_bus_param(icd,
- icd->current_fmt->host_fmt->fourcc);
+ ret = sh_mobile_ceu_set_bus_param(icd);
}
}
@@ -2089,6 +2098,9 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
goto exit_kfree;
}
+ pcdev->max_width = pcdev->pdata->max_width ? : 2560;
+ pcdev->max_height = pcdev->pdata->max_height ? : 1920;
+
base = ioremap_nocache(res->start, resource_size(res));
if (!base) {
err = -ENXIO;
diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c
index 8a652b53ff7e..05286500b4d4 100644
--- a/drivers/media/video/sh_mobile_csi2.c
+++ b/drivers/media/video/sh_mobile_csi2.c
@@ -390,18 +390,7 @@ static struct platform_driver __refdata sh_csi2_pdrv = {
},
};
-static int __init sh_csi2_init(void)
-{
- return platform_driver_register(&sh_csi2_pdrv);
-}
-
-static void __exit sh_csi2_exit(void)
-{
- platform_driver_unregister(&sh_csi2_pdrv);
-}
-
-module_init(sh_csi2_init);
-module_exit(sh_csi2_exit);
+module_platform_driver(sh_csi2_pdrv);
MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver");
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 7025be129286..c2882fa5be85 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -75,8 +75,8 @@ MODULE_PARM_DESC(video_nr,
"\none and for every other camera."
"\n");
-static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
- SN9C102_FORCE_MUNMAP};
+static bool force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
+ SN9C102_FORCE_MUNMAP};
module_param_array(force_munmap, bool, NULL, 0444);
MODULE_PARM_DESC(force_munmap,
" <0|1[,...]>"
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 62e4312515cb..eb25756a07af 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -487,7 +487,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
icd->user_width, icd->user_height);
/* set physical bus parameters */
- return ici->ops->set_bus_param(icd, pix->pixelformat);
+ return ici->ops->set_bus_param(icd);
}
static int soc_camera_open(struct file *file)
@@ -526,10 +526,6 @@ static int soc_camera_open(struct file *file)
},
};
- ret = soc_camera_power_on(icd, icl);
- if (ret < 0)
- goto epower;
-
/* The camera could have been already on, try to reset */
if (icl->reset)
icl->reset(icd->pdev);
@@ -540,6 +536,10 @@ static int soc_camera_open(struct file *file)
goto eiciadd;
}
+ ret = soc_camera_power_on(icd, icl);
+ if (ret < 0)
+ goto epower;
+
pm_runtime_enable(&icd->vdev->dev);
ret = pm_runtime_resume(&icd->vdev->dev);
if (ret < 0 && ret != -ENOSYS)
@@ -578,10 +578,10 @@ einitvb:
esfmt:
pm_runtime_disable(&icd->vdev->dev);
eresume:
- ici->ops->remove(icd);
-eiciadd:
soc_camera_power_off(icd, icl);
epower:
+ ici->ops->remove(icd);
+eiciadd:
icd->use_count--;
module_put(ici->ops->owner);
@@ -600,9 +600,9 @@ static int soc_camera_close(struct file *file)
pm_runtime_suspend(&icd->vdev->dev);
pm_runtime_disable(&icd->vdev->dev);
- ici->ops->remove(icd);
if (ici->ops->init_videobuf2)
vb2_queue_release(&icd->vb2_vidq);
+ ici->ops->remove(icd);
soc_camera_power_off(icd, icl);
}
@@ -1050,6 +1050,14 @@ static int soc_camera_probe(struct soc_camera_device *icd)
if (ret < 0)
goto ereg;
+ /* The camera could have been already on, try to reset */
+ if (icl->reset)
+ icl->reset(icd->pdev);
+
+ ret = ici->ops->add(icd);
+ if (ret < 0)
+ goto eadd;
+
/*
* This will not yet call v4l2_subdev_core_ops::s_power(1), because the
* subdevice has not been initialised yet. We'll have to call it once
@@ -1060,14 +1068,6 @@ static int soc_camera_probe(struct soc_camera_device *icd)
if (ret < 0)
goto epower;
- /* The camera could have been already on, try to reset */
- if (icl->reset)
- icl->reset(icd->pdev);
-
- ret = ici->ops->add(icd);
- if (ret < 0)
- goto eadd;
-
/* Must have icd->vdev before registering the device */
ret = video_dev_create(icd);
if (ret < 0)
@@ -1165,10 +1165,10 @@ eadddev:
video_device_release(icd->vdev);
icd->vdev = NULL;
evdc:
- ici->ops->remove(icd);
-eadd:
soc_camera_power_off(icd, icl);
epower:
+ ici->ops->remove(icd);
+eadd:
regulator_bulk_free(icl->num_regulators, icl->regulators);
ereg:
v4l2_ctrl_handler_free(&icd->ctrl_handler);
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
index 4402a8a74f7a..f59ccade07c8 100644
--- a/drivers/media/video/soc_camera_platform.c
+++ b/drivers/media/video/soc_camera_platform.c
@@ -189,18 +189,7 @@ static struct platform_driver soc_camera_platform_driver = {
.remove = soc_camera_platform_remove,
};
-static int __init soc_camera_platform_module_init(void)
-{
- return platform_driver_register(&soc_camera_platform_driver);
-}
-
-static void __exit soc_camera_platform_module_exit(void)
-{
- platform_driver_unregister(&soc_camera_platform_driver);
-}
-
-module_init(soc_camera_platform_module_init);
-module_exit(soc_camera_platform_module_exit);
+module_platform_driver(soc_camera_platform_driver);
MODULE_DESCRIPTION("SoC Camera Platform driver");
MODULE_AUTHOR("Magnus Damm");
diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/video/sr030pc30.c
index d1b07aceaf94..e9d95bda2ab1 100644
--- a/drivers/media/video/sr030pc30.c
+++ b/drivers/media/video/sr030pc30.c
@@ -864,18 +864,7 @@ static struct i2c_driver sr030pc30_i2c_driver = {
.id_table = sr030pc30_id,
};
-static int __init sr030pc30_init(void)
-{
- return i2c_add_driver(&sr030pc30_i2c_driver);
-}
-
-static void __exit sr030pc30_exit(void)
-{
- i2c_del_driver(&sr030pc30_i2c_driver);
-}
-
-module_init(sr030pc30_init);
-module_exit(sr030pc30_exit);
+module_i2c_driver(sr030pc30_i2c_driver);
MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index b7fb5a5cad7e..d427f8436c70 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -38,11 +38,11 @@
#include "stk-webcam.h"
-static int hflip = 1;
+static bool hflip = 1;
module_param(hflip, bool, 0444);
MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1");
-static int vflip = 1;
+static bool vflip = 1;
module_param(vflip, bool, 0444);
MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1");
@@ -377,8 +377,8 @@ static int stk_prepare_iso(struct stk_camera *dev)
if (dev->isobufs)
STK_ERROR("isobufs already allocated. Bad\n");
else
- dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs),
- GFP_KERNEL);
+ dev->isobufs = kcalloc(MAX_ISO_BUFS, sizeof(*dev->isobufs),
+ GFP_KERNEL);
if (dev->isobufs == NULL) {
STK_ERROR("Unable to allocate iso buffers\n");
return -ENOMEM;
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index bd218545da9c..f7707e65761e 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -482,15 +482,4 @@ static struct i2c_driver tda7432_driver = {
.id_table = tda7432_id,
};
-static __init int init_tda7432(void)
-{
- return i2c_add_driver(&tda7432_driver);
-}
-
-static __exit void exit_tda7432(void)
-{
- i2c_del_driver(&tda7432_driver);
-}
-
-module_init(init_tda7432);
-module_exit(exit_tda7432);
+module_i2c_driver(tda7432_driver);
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index 22fa8202d5ca..465d7086babf 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -208,15 +208,4 @@ static struct i2c_driver tda9840_driver = {
.id_table = tda9840_id,
};
-static __init int init_tda9840(void)
-{
- return i2c_add_driver(&tda9840_driver);
-}
-
-static __exit void exit_tda9840(void)
-{
- i2c_del_driver(&tda9840_driver);
-}
-
-module_init(init_tda9840);
-module_exit(exit_tda9840);
+module_i2c_driver(tda9840_driver);
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index 827425c5b866..d1d6ea1dd273 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -184,15 +184,4 @@ static struct i2c_driver tea6415c_driver = {
.id_table = tea6415c_id,
};
-static __init int init_tea6415c(void)
-{
- return i2c_add_driver(&tea6415c_driver);
-}
-
-static __exit void exit_tea6415c(void)
-{
- i2c_del_driver(&tea6415c_driver);
-}
-
-module_init(init_tea6415c);
-module_exit(exit_tea6415c);
+module_i2c_driver(tea6415c_driver);
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index f350b6c24500..38757217a074 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -166,15 +166,4 @@ static struct i2c_driver tea6420_driver = {
.id_table = tea6420_id,
};
-static __init int init_tea6420(void)
-{
- return i2c_add_driver(&tea6420_driver);
-}
-
-static __exit void exit_tea6420(void)
-{
- i2c_del_driver(&tea6420_driver);
-}
-
-module_init(init_tea6420);
-module_exit(exit_tea6420);
+module_i2c_driver(tea6420_driver);
diff --git a/drivers/media/video/ths7303.c b/drivers/media/video/ths7303.c
index 61b1dd118364..e5c0eedebc58 100644
--- a/drivers/media/video/ths7303.c
+++ b/drivers/media/video/ths7303.c
@@ -137,16 +137,4 @@ static struct i2c_driver ths7303_driver = {
.id_table = ths7303_id,
};
-static int __init ths7303_init(void)
-{
- return i2c_add_driver(&ths7303_driver);
-}
-
-static void __exit ths7303_exit(void)
-{
- i2c_del_driver(&ths7303_driver);
-}
-
-module_init(ths7303_init);
-module_exit(ths7303_exit);
-
+module_i2c_driver(ths7303_driver);
diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c
index a0895bf07487..02194c056b00 100644
--- a/drivers/media/video/timblogiw.c
+++ b/drivers/media/video/timblogiw.c
@@ -564,8 +564,8 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
spin_unlock_irq(&fh->queue_lock);
- desc = fh->chan->device->device_prep_slave_sg(fh->chan,
- buf->sg, sg_elems, DMA_FROM_DEVICE,
+ desc = dmaengine_prep_slave_sg(fh->chan,
+ buf->sg, sg_elems, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
if (!desc) {
spin_lock_irq(&fh->queue_lock);
@@ -872,20 +872,7 @@ static struct platform_driver timblogiw_platform_driver = {
.remove = __devexit_p(timblogiw_remove),
};
-/* Module functions */
-
-static int __init timblogiw_init(void)
-{
- return platform_driver_register(&timblogiw_platform_driver);
-}
-
-static void __exit timblogiw_exit(void)
-{
- platform_driver_unregister(&timblogiw_platform_driver);
-}
-
-module_init(timblogiw_init);
-module_exit(timblogiw_exit);
+module_platform_driver(timblogiw_platform_driver);
MODULE_DESCRIPTION(TIMBLOGIWIN_NAME);
MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>");
diff --git a/drivers/media/video/tlg2300/pd-common.h b/drivers/media/video/tlg2300/pd-common.h
index 56564e6aaac2..5dd73b7857d1 100644
--- a/drivers/media/video/tlg2300/pd-common.h
+++ b/drivers/media/video/tlg2300/pd-common.h
@@ -140,7 +140,7 @@ struct pd_dvb_adapter {
u8 reserved[3];
/* data for power resume*/
- struct dvb_frontend_parameters fe_param;
+ struct dtv_frontend_properties fe_param;
/* for channel scanning */
int prev_freq;
diff --git a/drivers/media/video/tlg2300/pd-dvb.c b/drivers/media/video/tlg2300/pd-dvb.c
index d0da11ae19df..30fcb117e898 100644
--- a/drivers/media/video/tlg2300/pd-dvb.c
+++ b/drivers/media/video/tlg2300/pd-dvb.c
@@ -12,9 +12,9 @@
static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb);
static int dvb_bandwidth[][2] = {
- { TLG_BW_8, BANDWIDTH_8_MHZ },
- { TLG_BW_7, BANDWIDTH_7_MHZ },
- { TLG_BW_6, BANDWIDTH_6_MHZ }
+ { TLG_BW_8, 8000000 },
+ { TLG_BW_7, 7000000 },
+ { TLG_BW_6, 6000000 }
};
static int dvb_bandwidth_length = ARRAY_SIZE(dvb_bandwidth);
@@ -146,9 +146,9 @@ static int fw_delay_overflow(struct pd_dvb_adapter *adapter)
return msec > 800 ? true : false;
}
-static int poseidon_set_fe(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int poseidon_set_fe(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
s32 ret = 0, cmd_status = 0;
s32 i, bandwidth = -1;
struct poseidon *pd = fe->demodulator_priv;
@@ -159,7 +159,7 @@ static int poseidon_set_fe(struct dvb_frontend *fe,
mutex_lock(&pd->lock);
for (i = 0; i < dvb_bandwidth_length; i++)
- if (fep->u.ofdm.bandwidth == dvb_bandwidth[i][1])
+ if (fep->bandwidth_hz == dvb_bandwidth[i][1])
bandwidth = dvb_bandwidth[i][0];
if (check_scan_ok(fep->frequency, bandwidth, pd_dvb)) {
@@ -210,7 +210,7 @@ static int pm_dvb_resume(struct poseidon *pd)
poseidon_check_mode_dvbt(pd);
msleep(300);
- poseidon_set_fe(&pd_dvb->dvb_fe, &pd_dvb->fe_param);
+ poseidon_set_fe(&pd_dvb->dvb_fe);
dvb_start_streaming(pd_dvb);
return 0;
@@ -227,13 +227,13 @@ static s32 poseidon_fe_init(struct dvb_frontend *fe)
pd->pm_resume = pm_dvb_resume;
#endif
memset(&pd_dvb->fe_param, 0,
- sizeof(struct dvb_frontend_parameters));
+ sizeof(struct dtv_frontend_properties));
return 0;
}
-static int poseidon_get_fe(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int poseidon_get_fe(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct poseidon *pd = fe->demodulator_priv;
struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
@@ -332,9 +332,9 @@ static int poseidon_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
}
static struct dvb_frontend_ops poseidon_frontend_ops = {
+ .delsys = { SYS_DVBT },
.info = {
.name = "Poseidon DVB-T",
- .type = FE_OFDM,
.frequency_min = 174000000,
.frequency_max = 862000000,
.frequency_stepsize = 62500,/* FIXME */
diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c
index 129f135d5a5f..c096b3f74200 100644
--- a/drivers/media/video/tlg2300/pd-main.c
+++ b/drivers/media/video/tlg2300/pd-main.c
@@ -374,7 +374,7 @@ static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
}
#endif
-static bool check_firmware(struct usb_device *udev, int *down_firmware)
+static int check_firmware(struct usb_device *udev, int *down_firmware)
{
void *buf;
int ret;
@@ -398,7 +398,7 @@ static bool check_firmware(struct usb_device *udev, int *down_firmware)
*down_firmware = 1;
return firmware_download(udev);
}
- return ret;
+ return 0;
}
static int poseidon_probe(struct usb_interface *interface,
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
index 286ec7e7062a..809a75a558ee 100644
--- a/drivers/media/video/tlv320aic23b.c
+++ b/drivers/media/video/tlv320aic23b.c
@@ -227,15 +227,4 @@ static struct i2c_driver tlv320aic23b_driver = {
.id_table = tlv320aic23b_id,
};
-static __init int init_tlv320aic23b(void)
-{
- return i2c_add_driver(&tlv320aic23b_driver);
-}
-
-static __exit void exit_tlv320aic23b(void)
-{
- i2c_del_driver(&tlv320aic23b_driver);
-}
-
-module_init(init_tlv320aic23b);
-module_exit(exit_tlv320aic23b);
+module_i2c_driver(tlv320aic23b_driver);
diff --git a/drivers/media/video/tm6000/Kconfig b/drivers/media/video/tm6000/Kconfig
index 114eec8a630a..a43b77abd931 100644
--- a/drivers/media/video/tm6000/Kconfig
+++ b/drivers/media/video/tm6000/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_TM6000
tristate "TV Master TM5600/6000/6010 driver"
- depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL
+ depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB
select VIDEO_TUNER
select MEDIA_TUNER_XC2028
select MEDIA_TUNER_XC5000
@@ -16,7 +16,7 @@ config VIDEO_TM6000
config VIDEO_TM6000_ALSA
tristate "TV Master TM5600/6000/6010 audio support"
- depends on VIDEO_TM6000 && SND && EXPERIMENTAL
+ depends on VIDEO_TM6000 && SND
select SND_PCM
---help---
This is a video4linux driver for direct (DMA) audio for
@@ -27,7 +27,7 @@ config VIDEO_TM6000_ALSA
config VIDEO_TM6000_DVB
tristate "DVB Support for tm6000 based TV cards"
- depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL
+ depends on VIDEO_TM6000 && DVB_CORE && USB
select DVB_ZL10353
---help---
This adds support for DVB cards based on the tm5600/tm6000 chip.
diff --git a/drivers/media/video/tm6000/tm6000-alsa.c b/drivers/media/video/tm6000/tm6000-alsa.c
index 7d675c72fd47..bd07ec707956 100644
--- a/drivers/media/video/tm6000/tm6000-alsa.c
+++ b/drivers/media/video/tm6000/tm6000-alsa.c
@@ -42,7 +42,7 @@
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
@@ -146,20 +146,21 @@ static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
#define DEFAULT_FIFO_SIZE 4096
static struct snd_pcm_hardware snd_tm6000_digital_hw = {
- .info = SNDRV_PCM_INFO_MMAP |
+ .info = SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.period_bytes_min = 64,
.period_bytes_max = 12544,
- .periods_min = 1,
+ .periods_min = 2,
.periods_max = 98,
.buffer_bytes_max = 62720 * 8,
};
@@ -181,6 +182,7 @@ static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
chip->substream = substream;
runtime->hw = snd_tm6000_digital_hw;
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
return 0;
_error:
@@ -347,9 +349,13 @@ static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
int err = 0;
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
case SNDRV_PCM_TRIGGER_START:
atomic_set(&core->stream_started, 1);
break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
case SNDRV_PCM_TRIGGER_STOP:
atomic_set(&core->stream_started, 0);
break;
@@ -371,6 +377,14 @@ static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
return chip->buf_pos;
}
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+
+ return vmalloc_to_page(pageptr);
+}
+
/*
* operators
*/
@@ -383,6 +397,7 @@ static struct snd_pcm_ops snd_tm6000_pcm_ops = {
.prepare = snd_tm6000_prepare,
.trigger = snd_tm6000_card_trigger,
.pointer = snd_tm6000_pointer,
+ .page = snd_pcm_get_vmalloc_page,
};
/*
diff --git a/drivers/media/video/tm6000/tm6000-cards.c b/drivers/media/video/tm6000/tm6000-cards.c
index ff939bc0e0b9..034659b13174 100644
--- a/drivers/media/video/tm6000/tm6000-cards.c
+++ b/drivers/media/video/tm6000/tm6000-cards.c
@@ -351,6 +351,7 @@ static struct tm6000_board tm6000_boards[] = {
.tuner_addr = 0xc2 >> 1,
.demod_addr = 0x1e >> 1,
.type = TM6010,
+ .ir_codes = RC_MAP_HAUPPAUGE,
.caps = {
.has_tuner = 1,
.has_dvb = 1,
@@ -639,6 +640,7 @@ static struct usb_device_id tm6000_id_table[] = {
{ USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
{ }
};
+MODULE_DEVICE_TABLE(usb, tm6000_id_table);
/* Control power led for show some activity */
void tm6000_flash_led(struct tm6000_core *dev, u8 state)
@@ -941,6 +943,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
case TM6010_BOARD_HAUPPAUGE_900H:
case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
case TM6010_BOARD_TWINHAN_TU501:
+ ctl.max_len = 80;
ctl.fname = "xc3028L-v36.fw";
break;
default:
@@ -1002,6 +1005,7 @@ static int fill_board_specific_data(struct tm6000_core *dev)
/* setup per-model quirks */
switch (dev->model) {
case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+ case TM6010_BOARD_HAUPPAUGE_900H:
dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
break;
@@ -1050,6 +1054,33 @@ static void use_alternative_detection_method(struct tm6000_core *dev)
tm6000_boards[model].name, model);
}
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+ struct tm6000_core *dev = container_of(work, struct tm6000_core,
+ request_module_wk);
+
+ request_module("tm6000-alsa");
+
+ if (dev->caps.has_dvb)
+ request_module("tm6000-dvb");
+}
+
+static void request_modules(struct tm6000_core *dev)
+{
+ INIT_WORK(&dev->request_module_wk, request_module_async);
+ schedule_work(&dev->request_module_wk);
+}
+
+static void flush_request_modules(struct tm6000_core *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#define flush_request_modules(dev)
+#endif /* CONFIG_MODULES */
+
static int tm6000_init_dev(struct tm6000_core *dev)
{
struct v4l2_frequency f;
@@ -1112,6 +1143,8 @@ static int tm6000_init_dev(struct tm6000_core *dev)
tm6000_ir_init(dev);
+ request_modules(dev);
+
mutex_unlock(&dev->lock);
return 0;
@@ -1324,6 +1357,8 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
+ flush_request_modules(dev);
+
tm6000_ir_fini(dev);
if (dev->gpio.power_led) {
diff --git a/drivers/media/video/tm6000/tm6000-core.c b/drivers/media/video/tm6000/tm6000-core.c
index 9783616a0da2..22cc0116deb6 100644
--- a/drivers/media/video/tm6000/tm6000-core.c
+++ b/drivers/media/video/tm6000/tm6000-core.c
@@ -38,6 +38,7 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
int ret, i;
unsigned int pipe;
u8 *data = NULL;
+ int delay = 5000;
mutex_lock(&dev->usb_lock);
@@ -88,7 +89,20 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
}
kfree(data);
- msleep(5);
+
+ if (dev->quirks & TM6000_QUIRK_NO_USB_DELAY)
+ delay = 0;
+
+ if (req == REQ_16_SET_GET_I2C_WR1_RDN && !(req_type & USB_DIR_IN)) {
+ unsigned int tsleep;
+ /* Calculate delay time, 14000us for 64 bytes */
+ tsleep = (len * 200) + 200;
+ if (tsleep < delay)
+ tsleep = delay;
+ usleep_range(tsleep, tsleep + 1000);
+ }
+ else if (delay)
+ usleep_range(delay, delay + 1000);
mutex_unlock(&dev->usb_lock);
return ret;
@@ -125,14 +139,14 @@ int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
u8 new_index;
rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
- value, index, buf, 1);
+ value, 0, buf, 1);
if (rc < 0)
return rc;
new_index = (buf[0] & ~mask) | (index & mask);
- if (new_index == index)
+ if (new_index == buf[0])
return 0;
return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
@@ -536,16 +550,16 @@ static struct reg_init tm6010_init_tab[] = {
{ TM6010_REQ05_R18_IMASK7, 0x00 },
- { TM6010_REQ07_RD8_IR_LEADER1, 0xaa },
- { TM6010_REQ07_RD8_IR_LEADER0, 0x30 },
- { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 },
- { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 },
+ { TM6010_REQ07_RDC_IR_LEADER1, 0xaa },
+ { TM6010_REQ07_RDD_IR_LEADER0, 0x30 },
+ { TM6010_REQ07_RDE_IR_PULSE_CNT1, 0x20 },
+ { TM6010_REQ07_RDF_IR_PULSE_CNT0, 0xd0 },
{ REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
- { TM6010_REQ07_RD8_IR, 0x2f },
+ { TM6010_REQ07_RD8_IR, 0x0f },
/* set remote wakeup key:any key wakeup */
{ TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe },
- { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff },
+ { TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff },
};
int tm6000_init(struct tm6000_core *dev)
@@ -599,55 +613,6 @@ int tm6000_init(struct tm6000_core *dev)
return rc;
}
-int tm6000_reset(struct tm6000_core *dev)
-{
- int pipe;
- int err;
-
- msleep(500);
-
- err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 0);
- if (err < 0) {
- tm6000_err("failed to select interface %d, alt. setting 0\n",
- dev->isoc_in.bInterfaceNumber);
- return err;
- }
-
- err = usb_reset_configuration(dev->udev);
- if (err < 0) {
- tm6000_err("failed to reset configuration\n");
- return err;
- }
-
- if ((dev->quirks & TM6000_QUIRK_NO_USB_DELAY) == 0)
- msleep(5);
-
- /*
- * Not all devices have int_in defined
- */
- if (!dev->int_in.endp)
- return 0;
-
- err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 2);
- if (err < 0) {
- tm6000_err("failed to select interface %d, alt. setting 2\n",
- dev->isoc_in.bInterfaceNumber);
- return err;
- }
-
- msleep(5);
-
- pipe = usb_rcvintpipe(dev->udev,
- dev->int_in.endp->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-
- err = usb_clear_halt(dev->udev, pipe);
- if (err < 0) {
- tm6000_err("usb_clear_halt failed: %d\n", err);
- return err;
- }
-
- return 0;
-}
int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
{
@@ -696,11 +661,13 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev)
if (dev->dev_type == TM6010) {
/* Audio crossbar setting, default SIF1 */
u8 areg_f0;
+ u8 areg_07 = 0x10;
switch (dev->rinput.amux) {
case TM6000_AMUX_SIF1:
case TM6000_AMUX_SIF2:
areg_f0 = 0x03;
+ areg_07 = 0x30;
break;
case TM6000_AMUX_ADC1:
areg_f0 = 0x00;
@@ -720,6 +687,9 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev)
/* Set audio input crossbar */
tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
areg_f0, 0x0f);
+ /* Mux overflow workaround */
+ tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
+ areg_07, 0xf0);
} else {
u8 areg_eb;
/* Audio setting, default LINE1 */
diff --git a/drivers/media/video/tm6000/tm6000-dvb.c b/drivers/media/video/tm6000/tm6000-dvb.c
index 5e6c129a4beb..e1f3f66e1e63 100644
--- a/drivers/media/video/tm6000/tm6000-dvb.c
+++ b/drivers/media/video/tm6000/tm6000-dvb.c
@@ -89,9 +89,19 @@ static void tm6000_urb_received(struct urb *urb)
int ret;
struct tm6000_core *dev = urb->context;
- if (urb->status != 0)
+ switch (urb->status) {
+ case 0:
+ case -ETIMEDOUT:
+ break;
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ return;
+ default:
print_err_status(dev, 0, urb->status);
- else if (urb->actual_length > 0)
+ }
+
+ if (urb->actual_length > 0)
dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
urb->actual_length);
@@ -151,7 +161,7 @@ static int tm6000_start_stream(struct tm6000_core *dev)
printk(KERN_ERR "tm6000: pipe resetted\n");
/* mutex_lock(&tm6000_driver.open_close_mutex); */
- ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
+ ret = usb_submit_urb(dvb->bulk_urb, GFP_ATOMIC);
/* mutex_unlock(&tm6000_driver.open_close_mutex); */
if (ret) {
@@ -396,6 +406,11 @@ static int dvb_init(struct tm6000_core *dev)
if (!dev->caps.has_dvb)
return 0;
+ if (dev->udev->speed == USB_SPEED_FULL) {
+ printk(KERN_INFO "This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)\n");
+ return 0;
+ }
+
dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
if (!dvb) {
printk(KERN_INFO "Cannot allocate memory\n");
diff --git a/drivers/media/video/tm6000/tm6000-i2c.c b/drivers/media/video/tm6000/tm6000-i2c.c
index 0290bbf00c3e..c7e23e3dd75e 100644
--- a/drivers/media/video/tm6000/tm6000-i2c.c
+++ b/drivers/media/video/tm6000/tm6000-i2c.c
@@ -46,11 +46,10 @@ static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
__u8 reg, char *buf, int len)
{
int rc;
- unsigned int tsleep;
unsigned int i2c_packet_limit = 16;
if (dev->dev_type == TM6010)
- i2c_packet_limit = 64;
+ i2c_packet_limit = 80;
if (!buf)
return -1;
@@ -71,10 +70,6 @@ static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
return rc;
}
- /* Calculate delay time, 14000us for 64 bytes */
- tsleep = ((len * 200) + 200 + 1000) / 1000;
- msleep(tsleep);
-
/* release mutex */
return rc;
}
@@ -145,7 +140,6 @@ static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr,
return rc;
}
- msleep(1400 / 1000);
rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ,
reg, 0, buf, len);
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c
index 405d12729d05..859eb90e4d56 100644
--- a/drivers/media/video/tm6000/tm6000-input.c
+++ b/drivers/media/video/tm6000/tm6000-input.c
@@ -31,22 +31,25 @@
static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug, "enable debug message [IR]");
+MODULE_PARM_DESC(ir_debug, "debug message level");
static unsigned int enable_ir = 1;
module_param(enable_ir, int, 0644);
MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
-/* number of 50ms for ON-OFF-ON power led */
-/* show IR activity */
-#define PWLED_OFF 2
+static unsigned int ir_clock_mhz = 12;
+module_param(ir_clock_mhz, int, 0644);
+MODULE_PARM_DESC(enable_ir, "ir clock, in MHz");
+
+#define URB_SUBMIT_DELAY 100 /* ms - Delay to submit an URB request on retrial and init */
+#define URB_INT_LED_DELAY 100 /* ms - Delay to turn led on again on int mode */
#undef dprintk
-#define dprintk(fmt, arg...) \
- if (ir_debug) { \
+#define dprintk(level, fmt, arg...) do {\
+ if (ir_debug >= level) \
printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
- }
+ } while (0)
struct tm6000_ir_poll_result {
u16 rc_data;
@@ -62,20 +65,15 @@ struct tm6000_IR {
int polling;
struct delayed_work work;
u8 wait:1;
- u8 key:1;
- u8 pwled:1;
- u8 pwledcnt;
+ u8 pwled:2;
+ u8 submit_urb:1;
u16 key_addr;
struct urb *int_urb;
- u8 *urb_data;
-
- int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
/* IR device properties */
u64 rc_type;
};
-
void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
{
struct tm6000_IR *ir = dev->ir;
@@ -83,62 +81,84 @@ void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
if (!dev->ir)
return;
+ dprintk(2, "%s: %i\n",__func__, ir->wait);
+
if (state)
ir->wait = 1;
else
ir->wait = 0;
}
-
static int tm6000_ir_config(struct tm6000_IR *ir)
{
struct tm6000_core *dev = ir->dev;
- u8 buf[10];
- int rc;
+ u32 pulse = 0, leader = 0;
+
+ dprintk(2, "%s\n",__func__);
+
+ /*
+ * The IR decoder supports RC-5 or NEC, with a configurable timing.
+ * The timing configuration there is not that accurate, as it uses
+ * approximate values. The NEC spec mentions a 562.5 unit period,
+ * and RC-5 uses a 888.8 period.
+ * Currently, driver assumes a clock provided by a 12 MHz XTAL, but
+ * a modprobe parameter can adjust it.
+ * Adjustments are required for other timings.
+ * It seems that the 900ms timing for NEC is used to detect a RC-5
+ * IR, in order to discard such decoding
+ */
switch (ir->rc_type) {
case RC_TYPE_NEC:
- /* Setup IR decoder for NEC standard 12MHz system clock */
- /* IR_LEADER_CNT = 0.9ms */
- tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa);
- tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30);
- /* IR_PULSE_CNT = 0.7ms */
- tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20);
- tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0);
- /* Remote WAKEUP = enable */
- tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
- /* IR_WKUP_SEL = Low byte in decoded IR data */
- tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff);
- /* IR_WKU_ADD code */
- tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff);
- tm6000_flash_led(dev, 0);
- msleep(100);
- tm6000_flash_led(dev, 1);
+ leader = 900; /* ms */
+ pulse = 700; /* ms - the actual value would be 562 */
break;
default:
- /* hack */
- buf[0] = 0xff;
- buf[1] = 0xff;
- buf[2] = 0xf2;
- buf[3] = 0x2b;
- buf[4] = 0x20;
- buf[5] = 0x35;
- buf[6] = 0x60;
- buf[7] = 0x04;
- buf[8] = 0xc0;
- buf[9] = 0x08;
-
- rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
- msleep(100);
-
- if (rc < 0) {
- printk(KERN_INFO "IR configuration failed");
- return rc;
- }
+ case RC_TYPE_RC5:
+ leader = 900; /* ms - from the NEC decoding */
+ pulse = 1780; /* ms - The actual value would be 1776 */
break;
}
+ pulse = ir_clock_mhz * pulse;
+ leader = ir_clock_mhz * leader;
+ if (ir->rc_type == RC_TYPE_NEC)
+ leader = leader | 0x8000;
+
+ dprintk(2, "%s: %s, %d MHz, leader = 0x%04x, pulse = 0x%06x \n",
+ __func__,
+ (ir->rc_type == RC_TYPE_NEC) ? "NEC" : "RC-5",
+ ir_clock_mhz, leader, pulse);
+
+ /* Remote WAKEUP = enable, normal mode, from IR decoder output */
+ tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
+
+ /* Enable IR reception on non-busrt mode */
+ tm6000_set_reg(dev, TM6010_REQ07_RD8_IR, 0x2f);
+
+ /* IR_WKUP_SEL = Low byte in decoded IR data */
+ tm6000_set_reg(dev, TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff);
+ /* IR_WKU_ADD code */
+ tm6000_set_reg(dev, TM6010_REQ07_RDB_IR_WAKEUP_ADD, 0xff);
+
+ tm6000_set_reg(dev, TM6010_REQ07_RDC_IR_LEADER1, leader >> 8);
+ tm6000_set_reg(dev, TM6010_REQ07_RDD_IR_LEADER0, leader);
+
+ tm6000_set_reg(dev, TM6010_REQ07_RDE_IR_PULSE_CNT1, pulse >> 8);
+ tm6000_set_reg(dev, TM6010_REQ07_RDF_IR_PULSE_CNT0, pulse);
+
+ if (!ir->polling)
+ tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
+ else
+ tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
+ msleep(10);
+
+ /* Shows that IR is working via the LED */
+ tm6000_flash_led(dev, 0);
+ msleep(100);
+ tm6000_flash_led(dev, 1);
+ ir->pwled = 1;
+
return 0;
}
@@ -146,132 +166,124 @@ static void tm6000_ir_urb_received(struct urb *urb)
{
struct tm6000_core *dev = urb->context;
struct tm6000_IR *ir = dev->ir;
+ struct tm6000_ir_poll_result poll_result;
+ char *buf;
int rc;
- if (urb->status != 0)
- printk(KERN_INFO "not ready\n");
- else if (urb->actual_length > 0) {
- memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length);
+ dprintk(2, "%s\n",__func__);
+ if (urb->status < 0 || urb->actual_length <= 0) {
+ printk(KERN_INFO "tm6000: IR URB failure: status: %i, length %i\n",
+ urb->status, urb->actual_length);
+ ir->submit_urb = 1;
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
+ return;
+ }
+ buf = urb->transfer_buffer;
- dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0],
- ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]);
+ if (ir_debug)
+ print_hex_dump(KERN_DEBUG, "tm6000: IR data: ",
+ DUMP_PREFIX_OFFSET,16, 1,
+ buf, urb->actual_length, false);
- ir->key = 1;
- }
+ poll_result.rc_data = buf[0];
+ if (urb->actual_length > 1)
+ poll_result.rc_data |= buf[1] << 8;
+
+ dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data);
+ rc_keydown(ir->rc, poll_result.rc_data, 0);
rc = usb_submit_urb(urb, GFP_ATOMIC);
+ /*
+ * Flash the led. We can't do it here, as it is running on IRQ context.
+ * So, use the scheduler to do it, in a few ms.
+ */
+ ir->pwled = 2;
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(10));
}
-static int default_polling_getkey(struct tm6000_IR *ir,
- struct tm6000_ir_poll_result *poll_result)
+static void tm6000_ir_handle_key(struct work_struct *work)
{
+ struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
struct tm6000_core *dev = ir->dev;
+ struct tm6000_ir_poll_result poll_result;
int rc;
u8 buf[2];
- if (ir->wait && !&dev->int_in)
- return 0;
-
- if (&dev->int_in) {
- switch (ir->rc_type) {
- case RC_TYPE_RC5:
- poll_result->rc_data = ir->urb_data[0];
- break;
- case RC_TYPE_NEC:
- if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) {
- poll_result->rc_data = ir->urb_data[0]
- | ir->urb_data[1] << 8;
- }
- break;
- default:
- poll_result->rc_data = ir->urb_data[0]
- | ir->urb_data[1] << 8;
- break;
- }
- } else {
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
- msleep(10);
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
- msleep(10);
-
- if (ir->rc_type == RC_TYPE_RC5) {
- rc = tm6000_read_write_usb(dev, USB_DIR_IN |
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- REQ_02_GET_IR_CODE, 0, 0, buf, 1);
-
- msleep(10);
-
- dprintk("read data=%02x\n", buf[0]);
- if (rc < 0)
- return rc;
+ if (ir->wait)
+ return;
- poll_result->rc_data = buf[0];
- } else {
- rc = tm6000_read_write_usb(dev, USB_DIR_IN |
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- REQ_02_GET_IR_CODE, 0, 0, buf, 2);
+ dprintk(3, "%s\n",__func__);
- msleep(10);
+ rc = tm6000_read_write_usb(dev, USB_DIR_IN |
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ REQ_02_GET_IR_CODE, 0, 0, buf, 2);
+ if (rc < 0)
+ return;
- dprintk("read data=%04x\n", buf[0] | buf[1] << 8);
- if (rc < 0)
- return rc;
+ if (rc > 1)
+ poll_result.rc_data = buf[0] | buf[1] << 8;
+ else
+ poll_result.rc_data = buf[0];
- poll_result->rc_data = buf[0] | buf[1] << 8;
+ /* Check if something was read */
+ if ((poll_result.rc_data & 0xff) == 0xff) {
+ if (!ir->pwled) {
+ tm6000_flash_led(dev, 1);
+ ir->pwled = 1;
}
- if ((poll_result->rc_data & 0x00ff) != 0xff)
- ir->key = 1;
+ return;
}
- return 0;
+
+ dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data);
+ rc_keydown(ir->rc, poll_result.rc_data, 0);
+ tm6000_flash_led(dev, 0);
+ ir->pwled = 0;
+
+ /* Re-schedule polling */
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
}
-static void tm6000_ir_handle_key(struct tm6000_IR *ir)
+static void tm6000_ir_int_work(struct work_struct *work)
{
+ struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
struct tm6000_core *dev = ir->dev;
- int result;
- struct tm6000_ir_poll_result poll_result;
+ int rc;
- /* read the registers containing the IR status */
- result = ir->get_key(ir, &poll_result);
- if (result < 0) {
- printk(KERN_INFO "ir->get_key() failed %d\n", result);
- return;
- }
+ dprintk(3, "%s, submit_urb = %d, pwled = %d\n",__func__, ir->submit_urb,
+ ir->pwled);
- dprintk("ir->get_key result data=%04x\n", poll_result.rc_data);
+ if (ir->submit_urb) {
+ dprintk(3, "Resubmit urb\n");
+ tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
- if (ir->pwled) {
- if (ir->pwledcnt >= PWLED_OFF) {
- ir->pwled = 0;
- ir->pwledcnt = 0;
- tm6000_flash_led(dev, 1);
- } else
- ir->pwledcnt += 1;
+ rc = usb_submit_urb(ir->int_urb, GFP_ATOMIC);
+ if (rc < 0) {
+ printk(KERN_ERR "tm6000: Can't submit an IR interrupt. Error %i\n",
+ rc);
+ /* Retry in 100 ms */
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
+ return;
+ }
+ ir->submit_urb = 0;
}
- if (ir->key) {
- rc_keydown(ir->rc, poll_result.rc_data, 0);
- ir->key = 0;
- ir->pwled = 1;
- ir->pwledcnt = 0;
+ /* Led is enabled only if USB submit doesn't fail */
+ if (ir->pwled == 2) {
tm6000_flash_led(dev, 0);
+ ir->pwled = 0;
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_INT_LED_DELAY));
+ } else if (!ir->pwled) {
+ tm6000_flash_led(dev, 1);
+ ir->pwled = 1;
}
- return;
-}
-
-static void tm6000_ir_work(struct work_struct *work)
-{
- struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
-
- tm6000_ir_handle_key(ir);
- schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
}
static int tm6000_ir_start(struct rc_dev *rc)
{
struct tm6000_IR *ir = rc->priv;
- INIT_DELAYED_WORK(&ir->work, tm6000_ir_work);
+ dprintk(2, "%s\n",__func__);
+
schedule_delayed_work(&ir->work, 0);
return 0;
@@ -281,6 +293,8 @@ static void tm6000_ir_stop(struct rc_dev *rc)
{
struct tm6000_IR *ir = rc->priv;
+ dprintk(2, "%s\n",__func__);
+
cancel_delayed_work_sync(&ir->work);
}
@@ -291,10 +305,11 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
if (!ir)
return 0;
+ dprintk(2, "%s\n",__func__);
+
if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC))
ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
- ir->get_key = default_polling_getkey;
ir->rc_type = rc_type;
tm6000_ir_config(ir);
@@ -302,17 +317,19 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
return 0;
}
-int tm6000_ir_int_start(struct tm6000_core *dev)
+static int __tm6000_ir_int_start(struct rc_dev *rc)
{
- struct tm6000_IR *ir = dev->ir;
+ struct tm6000_IR *ir = rc->priv;
+ struct tm6000_core *dev = ir->dev;
int pipe, size;
int err = -ENOMEM;
-
if (!ir)
return -ENODEV;
- ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+ dprintk(2, "%s\n",__func__);
+
+ ir->int_urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!ir->int_urb)
return -ENOMEM;
@@ -321,42 +338,59 @@ int tm6000_ir_int_start(struct tm6000_core *dev)
& USB_ENDPOINT_NUMBER_MASK);
size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
- dprintk("IR max size: %d\n", size);
+ dprintk(1, "IR max size: %d\n", size);
- ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+ ir->int_urb->transfer_buffer = kzalloc(size, GFP_ATOMIC);
if (ir->int_urb->transfer_buffer == NULL) {
usb_free_urb(ir->int_urb);
return err;
}
- dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
+ dprintk(1, "int interval: %d\n", dev->int_in.endp->desc.bInterval);
+
usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
ir->int_urb->transfer_buffer, size,
tm6000_ir_urb_received, dev,
dev->int_in.endp->desc.bInterval);
- err = usb_submit_urb(ir->int_urb, GFP_KERNEL);
- if (err) {
- kfree(ir->int_urb->transfer_buffer);
- usb_free_urb(ir->int_urb);
- return err;
- }
- ir->urb_data = kzalloc(size, GFP_KERNEL);
+
+ ir->submit_urb = 1;
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
return 0;
}
-void tm6000_ir_int_stop(struct tm6000_core *dev)
+static void __tm6000_ir_int_stop(struct rc_dev *rc)
{
- struct tm6000_IR *ir = dev->ir;
+ struct tm6000_IR *ir = rc->priv;
- if (!ir)
+ if (!ir || !ir->int_urb)
return;
+ dprintk(2, "%s\n",__func__);
+
usb_kill_urb(ir->int_urb);
kfree(ir->int_urb->transfer_buffer);
usb_free_urb(ir->int_urb);
ir->int_urb = NULL;
- kfree(ir->urb_data);
- ir->urb_data = NULL;
+}
+
+int tm6000_ir_int_start(struct tm6000_core *dev)
+{
+ struct tm6000_IR *ir = dev->ir;
+
+ if (!ir)
+ return 0;
+
+ return __tm6000_ir_int_start(ir->rc);
+}
+
+void tm6000_ir_int_stop(struct tm6000_core *dev)
+{
+ struct tm6000_IR *ir = dev->ir;
+
+ if (!ir || !ir->rc)
+ return;
+
+ __tm6000_ir_int_stop(ir->rc);
}
int tm6000_ir_init(struct tm6000_core *dev)
@@ -374,29 +408,36 @@ int tm6000_ir_init(struct tm6000_core *dev)
if (!dev->ir_codes)
return 0;
- ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ ir = kzalloc(sizeof(*ir), GFP_ATOMIC);
rc = rc_allocate_device();
if (!ir || !rc)
goto out;
+ dprintk(2, "%s\n", __func__);
+
/* record handles to ourself */
ir->dev = dev;
dev->ir = ir;
ir->rc = rc;
- /* input einrichten */
+ /* input setup */
rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
+ /* Neded, in order to support NEC remotes with 24 or 32 bits */
+ rc->scanmask = 0xffff;
rc->priv = ir;
rc->change_protocol = tm6000_ir_change_protocol;
- rc->open = tm6000_ir_start;
- rc->close = tm6000_ir_stop;
+ if (dev->int_in.endp) {
+ rc->open = __tm6000_ir_int_start;
+ rc->close = __tm6000_ir_int_stop;
+ INIT_DELAYED_WORK(&ir->work, tm6000_ir_int_work);
+ } else {
+ rc->open = tm6000_ir_start;
+ rc->close = tm6000_ir_stop;
+ ir->polling = 50;
+ INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key);
+ }
rc->driver_type = RC_DRIVER_SCANCODE;
- ir->polling = 50;
- ir->pwled = 0;
- ir->pwledcnt = 0;
-
-
snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
dev->name);
@@ -415,15 +456,6 @@ int tm6000_ir_init(struct tm6000_core *dev)
rc->driver_name = "tm6000";
rc->dev.parent = &dev->udev->dev;
- if (&dev->int_in) {
- dprintk("IR over int\n");
-
- err = tm6000_ir_int_start(dev);
-
- if (err)
- goto out;
- }
-
/* ir register */
err = rc_register_device(rc);
if (err)
@@ -447,10 +479,18 @@ int tm6000_ir_fini(struct tm6000_core *dev)
if (!ir)
return 0;
- rc_unregister_device(ir->rc);
+ dprintk(2, "%s\n",__func__);
+
+ if (!ir->polling)
+ __tm6000_ir_int_stop(ir->rc);
+
+ tm6000_ir_stop(ir->rc);
- if (ir->int_urb)
- tm6000_ir_int_stop(dev);
+ /* Turn off the led */
+ tm6000_flash_led(dev, 0);
+ ir->pwled = 0;
+
+ rc_unregister_device(ir->rc);
kfree(ir);
dev->ir = NULL;
diff --git a/drivers/media/video/tm6000/tm6000-regs.h b/drivers/media/video/tm6000/tm6000-regs.h
index 7f491b6de933..a38c251ed57b 100644
--- a/drivers/media/video/tm6000/tm6000-regs.h
+++ b/drivers/media/video/tm6000/tm6000-regs.h
@@ -284,19 +284,19 @@ enum {
/* ONLY for TM6010 */
#define TM6010_REQ07_RD8_IR 0x07, 0xd8
/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_BSIZE 0x07, 0xd9
+#define TM6010_REQ07_RD9_IR_BSIZE 0x07, 0xd9
/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_WAKEUP_SEL 0x07, 0xda
+#define TM6010_REQ07_RDA_IR_WAKEUP_SEL 0x07, 0xda
/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_WAKEUP_ADD 0x07, 0xdb
+#define TM6010_REQ07_RDB_IR_WAKEUP_ADD 0x07, 0xdb
/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_LEADER1 0x07, 0xdc
+#define TM6010_REQ07_RDC_IR_LEADER1 0x07, 0xdc
/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_LEADER0 0x07, 0xdd
+#define TM6010_REQ07_RDD_IR_LEADER0 0x07, 0xdd
/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_PULSE_CNT1 0x07, 0xde
+#define TM6010_REQ07_RDE_IR_PULSE_CNT1 0x07, 0xde
/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_PULSE_CNT0 0x07, 0xdf
+#define TM6010_REQ07_RDF_IR_PULSE_CNT0 0x07, 0xdf
/* ONLY for TM6010 */
#define TM6010_REQ07_RE0_DVIDEO_SOURCE 0x07, 0xe0
/* ONLY for TM6010 */
diff --git a/drivers/media/video/tm6000/tm6000-stds.c b/drivers/media/video/tm6000/tm6000-stds.c
index 9a4145dc3d87..9dc0831d813f 100644
--- a/drivers/media/video/tm6000/tm6000-stds.c
+++ b/drivers/media/video/tm6000/tm6000-stds.c
@@ -361,82 +361,51 @@ static int tm6000_set_audio_std(struct tm6000_core *dev)
return 0;
}
- switch (tm6010_a_mode) {
+ /*
+ * STD/MN shouldn't be affected by tm6010_a_mode, as there's just one
+ * audio standard for each V4L2_STD type.
+ */
+ if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_KR) {
+ areg_05 |= 0x04;
+ } else if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_JP) {
+ areg_05 |= 0x43;
+ } else if (dev->norm & V4L2_STD_MN) {
+ areg_05 |= 0x22;
+ } else switch (tm6010_a_mode) {
/* auto */
case 0:
- switch (dev->norm) {
- case V4L2_STD_NTSC_M_KR:
+ if ((dev->norm & V4L2_STD_SECAM) == V4L2_STD_SECAM_L)
areg_05 |= 0x00;
- break;
- case V4L2_STD_NTSC_M_JP:
- areg_05 |= 0x40;
- break;
- case V4L2_STD_NTSC_M:
- case V4L2_STD_PAL_M:
- case V4L2_STD_PAL_N:
- areg_05 |= 0x20;
- break;
- case V4L2_STD_PAL_Nc:
- areg_05 |= 0x60;
- break;
- case V4L2_STD_SECAM_L:
- areg_05 |= 0x00;
- break;
- case V4L2_STD_DK:
+ else /* Other PAL/SECAM standards */
areg_05 |= 0x10;
- break;
- }
break;
/* A2 */
case 1:
- switch (dev->norm) {
- case V4L2_STD_B:
- case V4L2_STD_GH:
- areg_05 = 0x05;
- break;
- case V4L2_STD_DK:
+ if (dev->norm & V4L2_STD_DK)
areg_05 = 0x09;
- break;
- }
+ else
+ areg_05 = 0x05;
break;
/* NICAM */
case 2:
- switch (dev->norm) {
- case V4L2_STD_B:
- case V4L2_STD_GH:
- areg_05 = 0x07;
- break;
- case V4L2_STD_DK:
+ if (dev->norm & V4L2_STD_DK) {
areg_05 = 0x06;
- break;
- case V4L2_STD_PAL_I:
+ } else if (dev->norm & V4L2_STD_PAL_I) {
areg_05 = 0x08;
- break;
- case V4L2_STD_SECAM_L:
+ } else if (dev->norm & V4L2_STD_SECAM_L) {
areg_05 = 0x0a;
areg_02 = 0x02;
- break;
+ } else {
+ areg_05 = 0x07;
}
nicam_flag = 1;
break;
/* other */
case 3:
- switch (dev->norm) {
- /* DK3_A2 */
- case V4L2_STD_DK:
+ if (dev->norm & V4L2_STD_DK) {
areg_05 = 0x0b;
- break;
- /* Korea */
- case V4L2_STD_NTSC_M_KR:
- areg_05 = 0x04;
- break;
- /* EIAJ */
- case V4L2_STD_NTSC_M_JP:
- areg_05 = 0x03;
- break;
- default:
+ } else {
areg_05 = 0x02;
- break;
}
break;
}
@@ -557,10 +526,16 @@ int tm6000_set_standard(struct tm6000_core *dev)
case TM6000_AMUX_ADC1:
tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
0x00, 0x0f);
+ /* Mux overflow workaround */
+ tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
+ 0x10, 0xf0);
break;
case TM6000_AMUX_ADC2:
tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
0x08, 0x0f);
+ /* Mux overflow workaround */
+ tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
+ 0x10, 0xf0);
break;
case TM6000_AMUX_SIF1:
reg_08_e2 |= 0x02;
@@ -570,6 +545,9 @@ int tm6000_set_standard(struct tm6000_core *dev)
tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
0x02, 0x0f);
+ /* Mux overflow workaround */
+ tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
+ 0x30, 0xf0);
break;
case TM6000_AMUX_SIF2:
reg_08_e2 |= 0x02;
@@ -579,6 +557,9 @@ int tm6000_set_standard(struct tm6000_core *dev)
tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7);
tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
0x02, 0x0f);
+ /* Mux overflow workaround */
+ tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
+ 0x30, 0xf0);
break;
default:
break;
diff --git a/drivers/media/video/tm6000/tm6000-video.c b/drivers/media/video/tm6000/tm6000-video.c
index 1e5ace0b5d10..bc13db736e24 100644
--- a/drivers/media/video/tm6000/tm6000-video.c
+++ b/drivers/media/video/tm6000/tm6000-video.c
@@ -1605,16 +1605,25 @@ static int tm6000_release(struct file *file)
res_free(dev, fh);
if (!dev->users) {
- int err;
-
tm6000_uninit_isoc(dev);
+ /* Stop interrupt USB pipe */
+ tm6000_ir_int_stop(dev);
+
+ usb_reset_configuration(dev->udev);
+
+ if (dev->int_in.endp)
+ usb_set_interface(dev->udev,
+ dev->isoc_in.bInterfaceNumber, 2);
+ else
+ usb_set_interface(dev->udev,
+ dev->isoc_in.bInterfaceNumber, 0);
+
+ /* Start interrupt USB pipe */
+ tm6000_ir_int_start(dev);
+
if (!fh->radio)
videobuf_mmap_free(&fh->vb_vidq);
-
- err = tm6000_reset(dev);
- if (err < 0)
- dev_err(&vdev->dev, "reset failed: %d\n", err);
}
kfree(fh);
diff --git a/drivers/media/video/tm6000/tm6000.h b/drivers/media/video/tm6000/tm6000.h
index 2777e514eff2..27ba659cfa85 100644
--- a/drivers/media/video/tm6000/tm6000.h
+++ b/drivers/media/video/tm6000/tm6000.h
@@ -188,6 +188,9 @@ struct tm6000_core {
/* Device Capabilities*/
struct tm6000_capabilities caps;
+ /* Used to load alsa/dvb */
+ struct work_struct request_module_wk;
+
/* Tuner configuration */
int tuner_type; /* type of the tuner */
int tuner_addr; /* tuner address */
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 11cc980b0cd5..a5c6397ad591 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -326,6 +326,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
t->mode_mask = T_RADIO;
break;
case TUNER_PHILIPS_FMD1216ME_MK3:
+ case TUNER_PHILIPS_FMD1216MEX_MK3:
buffer[0] = 0x0b;
buffer[1] = 0xdc;
buffer[2] = 0x9c;
@@ -379,6 +380,21 @@ static void set_type(struct i2c_client *c, unsigned int type,
tune_now = 0;
break;
}
+ case TUNER_XC5000C:
+ {
+ struct xc5000_config xc5000c_cfg = {
+ .i2c_address = t->i2c->addr,
+ /* if_khz will be set at dvb_attach() */
+ .if_khz = 0,
+ .chip_id = XC5000C,
+ };
+
+ if (!dvb_attach(xc5000_attach,
+ &t->fe, t->i2c->adapter, &xc5000c_cfg))
+ goto attach_failed;
+ tune_now = 0;
+ break;
+ }
case TUNER_NXP_TDA18271:
{
struct tda18271_config cfg = {
@@ -1313,18 +1329,7 @@ static struct i2c_driver tuner_driver = {
.id_table = tuner_id,
};
-static __init int init_tuner(void)
-{
- return i2c_add_driver(&tuner_driver);
-}
-
-static __exit void exit_tuner(void)
-{
- i2c_del_driver(&tuner_driver);
-}
-
-module_init(init_tuner);
-module_exit(exit_tuner);
+module_i2c_driver(tuner_driver);
MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index f22dbef9b95b..c5b1a7365e4f 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -2078,15 +2078,4 @@ static struct i2c_driver tvaudio_driver = {
.id_table = tvaudio_id,
};
-static __init int init_tvaudio(void)
-{
- return i2c_add_driver(&tvaudio_driver);
-}
-
-static __exit void exit_tvaudio(void)
-{
- i2c_del_driver(&tvaudio_driver);
-}
-
-module_init(init_tvaudio);
-module_exit(exit_tvaudio);
+module_i2c_driver(tvaudio_driver);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 6103d1b1081e..3b6cf034976a 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -286,8 +286,16 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "MaxLinear 301"},
{ TUNER_ABSENT, "Mirics MSi001"},
{ TUNER_ABSENT, "MaxLinear MxL241SF"},
- { TUNER_ABSENT, "Xceive XC5000C"},
+ { TUNER_XC5000C, "Xceive XC5000C"},
{ TUNER_ABSENT, "Montage M68TS2020"},
+ { TUNER_ABSENT, "Siano SMS1530"},
+ { TUNER_ABSENT, "Dibcom 7090"},
+ { TUNER_ABSENT, "Xceive XC5200C"},
+ { TUNER_ABSENT, "NXP 18273"},
+ { TUNER_ABSENT, "Montage M88TS2022"},
+ /* 180-189 */
+ { TUNER_ABSENT, "NXP 18272M"},
+ { TUNER_ABSENT, "NXP 18272S"},
};
/* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
index 926f03931156..cd615c1d6011 100644
--- a/drivers/media/video/tvp514x.c
+++ b/drivers/media/video/tvp514x.c
@@ -52,7 +52,7 @@
#define LOCK_RETRY_DELAY (200)
/* Debug functions */
-static int debug;
+static bool debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -1163,15 +1163,4 @@ static struct i2c_driver tvp514x_driver = {
.id_table = tvp514x_id,
};
-static int __init tvp514x_init(void)
-{
- return i2c_add_driver(&tvp514x_driver);
-}
-
-static void __exit tvp514x_exit(void)
-{
- i2c_del_driver(&tvp514x_driver);
-}
-
-module_init(tvp514x_init);
-module_exit(tvp514x_exit);
+module_i2c_driver(tvp514x_driver);
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index 6abaa16ae136..1326e11cf4a9 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -17,6 +17,13 @@
#include "tvp5150_reg.h"
+#define TVP5150_H_MAX 720
+#define TVP5150_V_MAX_525_60 480
+#define TVP5150_V_MAX_OTHERS 576
+#define TVP5150_MAX_CROP_LEFT 511
+#define TVP5150_MAX_CROP_TOP 127
+#define TVP5150_CROP_SHIFT 2
+
MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");
MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
@@ -29,6 +36,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
struct tvp5150 {
struct v4l2_subdev sd;
struct v4l2_ctrl_handler hdl;
+ struct v4l2_rect rect;
v4l2_std_id norm; /* Current set standard */
u32 input;
@@ -703,21 +711,21 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
/* First tests should be against specific std */
if (std == V4L2_STD_ALL) {
- fmt = 0; /* Autodetect mode */
+ fmt = VIDEO_STD_AUTO_SWITCH_BIT; /* Autodetect mode */
} else if (std & V4L2_STD_NTSC_443) {
- fmt = 0xa;
+ fmt = VIDEO_STD_NTSC_4_43_BIT;
} else if (std & V4L2_STD_PAL_M) {
- fmt = 0x6;
+ fmt = VIDEO_STD_PAL_M_BIT;
} else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
- fmt = 0x8;
+ fmt = VIDEO_STD_PAL_COMBINATION_N_BIT;
} else {
/* Then, test against generic ones */
if (std & V4L2_STD_NTSC)
- fmt = 0x2;
+ fmt = VIDEO_STD_NTSC_MJ_BIT;
else if (std & V4L2_STD_PAL)
- fmt = 0x4;
+ fmt = VIDEO_STD_PAL_BDGHIN_BIT;
else if (std & V4L2_STD_SECAM)
- fmt = 0xc;
+ fmt = VIDEO_STD_SECAM_BIT;
}
v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt);
@@ -732,6 +740,13 @@ static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
if (decoder->norm == std)
return 0;
+ /* Change cropping height limits */
+ if (std & V4L2_STD_525_60)
+ decoder->rect.height = TVP5150_V_MAX_525_60;
+ else
+ decoder->rect.height = TVP5150_V_MAX_OTHERS;
+
+
return tvp5150_set_std(sd, std);
}
@@ -779,6 +794,160 @@ static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
+static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
+{
+ int val = tvp5150_read(sd, TVP5150_STATUS_REG_5);
+
+ switch (val & 0x0F) {
+ case 0x01:
+ return V4L2_STD_NTSC;
+ case 0x03:
+ return V4L2_STD_PAL;
+ case 0x05:
+ return V4L2_STD_PAL_M;
+ case 0x07:
+ return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
+ case 0x09:
+ return V4L2_STD_NTSC_443;
+ case 0xb:
+ return V4L2_STD_SECAM;
+ default:
+ return V4L2_STD_UNKNOWN;
+ }
+}
+
+static int tvp5150_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index)
+ return -EINVAL;
+
+ *code = V4L2_MBUS_FMT_YUYV8_2X8;
+ return 0;
+}
+
+static int tvp5150_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *f)
+{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ v4l2_std_id std;
+
+ if (f == NULL)
+ return -EINVAL;
+
+ tvp5150_reset(sd, 0);
+
+ /* Calculate height and width based on current standard */
+ if (decoder->norm == V4L2_STD_ALL)
+ std = tvp5150_read_std(sd);
+ else
+ std = decoder->norm;
+
+ f->width = decoder->rect.width;
+ f->height = decoder->rect.height;
+
+ f->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ f->field = V4L2_FIELD_SEQ_TB;
+ f->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width,
+ f->height);
+ return 0;
+}
+
+static int tvp5150_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct v4l2_rect rect = a->c;
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ v4l2_std_id std;
+ int hmax;
+
+ v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n",
+ __func__, rect.left, rect.top, rect.width, rect.height);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* tvp5150 has some special limits */
+ rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
+ rect.width = clamp(rect.width,
+ TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
+ TVP5150_H_MAX - rect.left);
+ rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
+
+ /* Calculate height based on current standard */
+ if (decoder->norm == V4L2_STD_ALL)
+ std = tvp5150_read_std(sd);
+ else
+ std = decoder->norm;
+
+ if (std & V4L2_STD_525_60)
+ hmax = TVP5150_V_MAX_525_60;
+ else
+ hmax = TVP5150_V_MAX_OTHERS;
+
+ rect.height = clamp(rect.height,
+ hmax - TVP5150_MAX_CROP_TOP - rect.top,
+ hmax - rect.top);
+
+ tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top);
+ tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,
+ rect.top + rect.height - hmax);
+ tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB,
+ rect.left >> TVP5150_CROP_SHIFT);
+ tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB,
+ rect.left | (1 << TVP5150_CROP_SHIFT));
+ tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB,
+ (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
+ TVP5150_CROP_SHIFT);
+ tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB,
+ rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
+
+ decoder->rect = rect;
+
+ return 0;
+}
+
+static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+
+ a->c = decoder->rect;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+ v4l2_std_id std;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = TVP5150_H_MAX;
+
+ /* Calculate height based on current standard */
+ if (decoder->norm == V4L2_STD_ALL)
+ std = tvp5150_read_std(sd);
+ else
+ std = decoder->norm;
+
+ if (std & V4L2_STD_525_60)
+ a->bounds.height = TVP5150_V_MAX_525_60;
+ else
+ a->bounds.height = TVP5150_V_MAX_OTHERS;
+
+ a->defrect = a->bounds;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
/****************************************************************************
I2C Command
****************************************************************************/
@@ -931,6 +1100,13 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
.s_routing = tvp5150_s_routing,
+ .enum_mbus_fmt = tvp5150_enum_mbus_fmt,
+ .s_mbus_fmt = tvp5150_mbus_fmt,
+ .try_mbus_fmt = tvp5150_mbus_fmt,
+ .g_mbus_fmt = tvp5150_mbus_fmt,
+ .s_crop = tvp5150_s_crop,
+ .g_crop = tvp5150_g_crop,
+ .cropcap = tvp5150_cropcap,
};
static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
@@ -1016,6 +1192,15 @@ static int tvp5150_probe(struct i2c_client *c,
}
v4l2_ctrl_handler_setup(&core->hdl);
+ /* Default is no cropping */
+ core->rect.top = 0;
+ if (tvp5150_read_std(sd) & V4L2_STD_525_60)
+ core->rect.height = TVP5150_V_MAX_525_60;
+ else
+ core->rect.height = TVP5150_V_MAX_OTHERS;
+ core->rect.left = 0;
+ core->rect.width = TVP5150_H_MAX;
+
if (debug > 1)
tvp5150_log_status(sd);
return 0;
@@ -1054,15 +1239,4 @@ static struct i2c_driver tvp5150_driver = {
.id_table = tvp5150_id,
};
-static __init int init_tvp5150(void)
-{
- return i2c_add_driver(&tvp5150_driver);
-}
-
-static __exit void exit_tvp5150(void)
-{
- i2c_del_driver(&tvp5150_driver);
-}
-
-module_init(init_tvp5150);
-module_exit(exit_tvp5150);
+module_i2c_driver(tvp5150_driver);
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c
index 7875e80cb2ff..d7676d85c4df 100644
--- a/drivers/media/video/tvp7002.c
+++ b/drivers/media/video/tvp7002.c
@@ -63,7 +63,7 @@ MODULE_LICENSE("GPL");
#define TVP7002_CL_MASK 0x0f
/* Debug functions */
-static int debug;
+static bool debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-2)");
@@ -1069,27 +1069,4 @@ static struct i2c_driver tvp7002_driver = {
.id_table = tvp7002_id,
};
-/*
- * tvp7002_init - Initialize driver via I2C interface
- *
- * Register the TVP7002 driver.
- * Return 0 on success or error code on failure.
- */
-static int __init tvp7002_init(void)
-{
- return i2c_add_driver(&tvp7002_driver);
-}
-
-/*
- * tvp7002_exit - Remove driver via I2C interface
- *
- * Unregister the TVP7002 driver.
- * Returns nothing.
- */
-static void __exit tvp7002_exit(void)
-{
- i2c_del_driver(&tvp7002_driver);
-}
-
-module_init(tvp7002_init);
-module_exit(tvp7002_exit);
+module_i2c_driver(tvp7002_driver);
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index a514fa61116c..8768efb8508a 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -951,21 +951,7 @@ static struct i2c_driver tw9910_i2c_driver = {
.id_table = tw9910_id,
};
-/*
- * module function
- */
-static int __init tw9910_module_init(void)
-{
- return i2c_add_driver(&tw9910_i2c_driver);
-}
-
-static void __exit tw9910_module_exit(void)
-{
- i2c_del_driver(&tw9910_i2c_driver);
-}
-
-module_init(tw9910_module_init);
-module_exit(tw9910_module_exit);
+module_i2c_driver(tw9910_i2c_driver);
MODULE_DESCRIPTION("SoC Camera driver for tw9910");
MODULE_AUTHOR("Kuninori Morimoto");
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index 1aab96a88203..1e7446542091 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -271,15 +271,4 @@ static struct i2c_driver upd64031a_driver = {
.id_table = upd64031a_id,
};
-static __init int init_upd64031a(void)
-{
- return i2c_add_driver(&upd64031a_driver);
-}
-
-static __exit void exit_upd64031a(void)
-{
- i2c_del_driver(&upd64031a_driver);
-}
-
-module_init(init_upd64031a);
-module_exit(exit_upd64031a);
+module_i2c_driver(upd64031a_driver);
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index 9bbe61700fd5..75d6acc62018 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -34,7 +34,7 @@ MODULE_DESCRIPTION("uPD64083 driver");
MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
MODULE_LICENSE("GPL");
-static int debug;
+static bool debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -243,15 +243,4 @@ static struct i2c_driver upd64083_driver = {
.id_table = upd64083_id,
};
-static __init int init_upd64083(void)
-{
- return i2c_add_driver(&upd64083_driver);
-}
-
-static __exit void exit_upd64083(void)
-{
- i2c_del_driver(&upd64083_driver);
-}
-
-module_init(init_upd64083);
-module_exit(exit_upd64083);
+module_i2c_driver(upd64083_driver);
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index d7f97513b289..89fec029e924 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -110,42 +110,20 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap,
unsigned char addr;
int ret;
- if ((flags & I2C_M_TEN)) {
- /* a ten bit address */
- addr = 0xf0 | ((msg->addr >> 7) & 0x03);
- /* try extended address code... */
- ret = try_write_address(i2c_adap, addr, retries);
- if (ret != 1) {
- dev_err(&i2c_adap->dev,
- "died at extended address code, while writing\n");
- return -EREMOTEIO;
- }
- add[0] = addr;
- if (flags & I2C_M_RD) {
- /* okay, now switch into reading mode */
- addr |= 0x01;
- ret = try_read_address(i2c_adap, addr, retries);
- if (ret != 1) {
- dev_err(&i2c_adap->dev,
- "died at extended address code, while reading\n");
- return -EREMOTEIO;
- }
- }
- } else { /* normal 7bit address */
- addr = (msg->addr << 1);
- if (flags & I2C_M_RD)
- addr |= 1;
+ addr = (msg->addr << 1);
+ if (flags & I2C_M_RD)
+ addr |= 1;
- add[0] = addr;
- if (flags & I2C_M_RD)
- ret = try_read_address(i2c_adap, addr, retries);
- else
- ret = try_write_address(i2c_adap, addr, retries);
+ add[0] = addr;
+ if (flags & I2C_M_RD)
+ ret = try_read_address(i2c_adap, addr, retries);
+ else
+ ret = try_write_address(i2c_adap, addr, retries);
+
+ if (ret != 1)
+ return -EREMOTEIO;
- if (ret != 1)
- return -EREMOTEIO;
- }
return 0;
}
@@ -184,7 +162,7 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
static u32 functionality(struct i2c_adapter *adap)
{
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
/* -----exported algorithm data: ------------------------------------- */
diff --git a/drivers/media/video/uvc/Kconfig b/drivers/media/video/uvc/Kconfig
index 2956a7637219..6c197da531b2 100644
--- a/drivers/media/video/uvc/Kconfig
+++ b/drivers/media/video/uvc/Kconfig
@@ -1,5 +1,6 @@
config USB_VIDEO_CLASS
tristate "USB Video Class (UVC)"
+ select VIDEOBUF2_VMALLOC
---help---
Support for the USB Video Class (UVC). Currently only video
input devices, such as webcams, are supported.
diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile
index 2071ca8a2f03..c26d12fdb8f4 100644
--- a/drivers/media/video/uvc/Makefile
+++ b/drivers/media/video/uvc/Makefile
@@ -1,5 +1,5 @@
uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
- uvc_status.o uvc_isight.o
+ uvc_status.o uvc_isight.o uvc_debugfs.o
ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
uvcvideo-objs += uvc_entity.o
endif
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 254d32688843..0efd3b10b353 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -878,8 +878,21 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
ctrl->info.size);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ if (UVC_ENTITY_TYPE(ctrl->entity) !=
+ UVC_VC_EXTENSION_UNIT)
+ return ret;
+
+ /* GET_RES is mandatory for XU controls, but some
+ * cameras still choke on it. Ignore errors and set the
+ * resolution value to zero.
+ */
+ uvc_warn_once(chain->dev, UVC_WARN_XU_GET_RES,
+ "UVC non compliance - GET_RES failed on "
+ "an XU control. Enabling workaround.\n");
+ memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0,
+ ctrl->info.size);
+ }
}
ctrl->cached = 1;
@@ -1861,7 +1874,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
if (ncontrols == 0)
continue;
- entity->controls = kzalloc(ncontrols * sizeof(*ctrl),
+ entity->controls = kcalloc(ncontrols, sizeof(*ctrl),
GFP_KERNEL);
if (entity->controls == NULL)
return -ENOMEM;
diff --git a/drivers/media/video/uvc/uvc_debugfs.c b/drivers/media/video/uvc/uvc_debugfs.c
new file mode 100644
index 000000000000..14561a5abb79
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_debugfs.c
@@ -0,0 +1,136 @@
+/*
+ * uvc_debugfs.c -- USB Video Class driver - Debugging support
+ *
+ * Copyright (C) 2011
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "uvcvideo.h"
+
+/* -----------------------------------------------------------------------------
+ * Statistics
+ */
+
+#define UVC_DEBUGFS_BUF_SIZE 1024
+
+struct uvc_debugfs_buffer {
+ size_t count;
+ char data[UVC_DEBUGFS_BUF_SIZE];
+};
+
+static int uvc_debugfs_stats_open(struct inode *inode, struct file *file)
+{
+ struct uvc_streaming *stream = inode->i_private;
+ struct uvc_debugfs_buffer *buf;
+
+ buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ buf->count = uvc_video_stats_dump(stream, buf->data, sizeof(buf->data));
+
+ file->private_data = buf;
+ return 0;
+}
+
+static ssize_t uvc_debugfs_stats_read(struct file *file, char __user *user_buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct uvc_debugfs_buffer *buf = file->private_data;
+
+ return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data,
+ buf->count);
+}
+
+static int uvc_debugfs_stats_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ file->private_data = NULL;
+
+ return 0;
+}
+
+static const struct file_operations uvc_debugfs_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = uvc_debugfs_stats_open,
+ .llseek = no_llseek,
+ .read = uvc_debugfs_stats_read,
+ .release = uvc_debugfs_stats_release,
+};
+
+/* -----------------------------------------------------------------------------
+ * Global and stream initialization/cleanup
+ */
+
+static struct dentry *uvc_debugfs_root_dir;
+
+int uvc_debugfs_init_stream(struct uvc_streaming *stream)
+{
+ struct usb_device *udev = stream->dev->udev;
+ struct dentry *dent;
+ char dir_name[32];
+
+ if (uvc_debugfs_root_dir == NULL)
+ return -ENODEV;
+
+ sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum);
+
+ dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir);
+ if (IS_ERR_OR_NULL(dent)) {
+ uvc_printk(KERN_INFO, "Unable to create debugfs %s "
+ "directory.\n", dir_name);
+ return -ENODEV;
+ }
+
+ stream->debugfs_dir = dent;
+
+ dent = debugfs_create_file("stats", 0444, stream->debugfs_dir,
+ stream, &uvc_debugfs_stats_fops);
+ if (IS_ERR_OR_NULL(dent)) {
+ uvc_printk(KERN_INFO, "Unable to create debugfs stats file.\n");
+ uvc_debugfs_cleanup_stream(stream);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream)
+{
+ if (stream->debugfs_dir == NULL)
+ return;
+
+ debugfs_remove_recursive(stream->debugfs_dir);
+ stream->debugfs_dir = NULL;
+}
+
+int uvc_debugfs_init(void)
+{
+ struct dentry *dir;
+
+ dir = debugfs_create_dir("uvcvideo", usb_debug_root);
+ if (IS_ERR_OR_NULL(dir)) {
+ uvc_printk(KERN_INFO, "Unable to create debugfs directory\n");
+ return -ENODATA;
+ }
+
+ uvc_debugfs_root_dir = dir;
+ return 0;
+}
+
+void uvc_debugfs_cleanup(void)
+{
+ if (uvc_debugfs_root_dir != NULL)
+ debugfs_remove_recursive(uvc_debugfs_root_dir);
+}
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 656d4c9e3b9f..1d131720b6d7 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -23,6 +23,7 @@
* codec can't handle MJPEG data.
*/
+#include <linux/atomic.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -32,7 +33,6 @@
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <linux/version.h>
-#include <asm/atomic.h>
#include <asm/unaligned.h>
#include <media/v4l2-common.h>
@@ -1675,6 +1675,8 @@ static void uvc_unregister_video(struct uvc_device *dev)
video_unregister_device(stream->vdev);
stream->vdev = NULL;
+
+ uvc_debugfs_cleanup_stream(stream);
}
/* Decrement the stream count and call uvc_delete explicitly if there
@@ -1700,6 +1702,8 @@ static int uvc_register_video(struct uvc_device *dev,
return ret;
}
+ uvc_debugfs_init_stream(stream);
+
/* Register the device with V4L. */
vdev = video_device_alloc();
if (vdev == NULL) {
@@ -2033,6 +2037,15 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
* though they are compliant.
*/
static struct usb_device_id uvc_ids[] = {
+ /* LogiLink Wireless Webcam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0416,
+ .idProduct = 0xa91a,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
/* Genius eFace 2025 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2126,6 +2139,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Dell XPS m1530 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05a9,
+ .idProduct = 0x2640,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_DEF },
/* Apple Built-In iSight */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2396,17 +2418,24 @@ struct uvc_driver uvc_driver = {
static int __init uvc_init(void)
{
- int result;
+ int ret;
+
+ uvc_debugfs_init();
- result = usb_register(&uvc_driver.driver);
- if (result == 0)
- printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
- return result;
+ ret = usb_register(&uvc_driver.driver);
+ if (ret < 0) {
+ uvc_debugfs_cleanup();
+ return ret;
+ }
+
+ printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
+ return 0;
}
static void __exit uvc_cleanup(void)
{
usb_deregister(&uvc_driver.driver);
+ uvc_debugfs_cleanup();
}
module_init(uvc_init);
diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c
index 74bbe8f18f3e..8510e7259e76 100644
--- a/drivers/media/video/uvc/uvc_isight.c
+++ b/drivers/media/video/uvc/uvc_isight.c
@@ -74,7 +74,7 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
* Empty buffers (bytesused == 0) don't trigger end of frame detection
* as it doesn't make sense to return an empty buffer.
*/
- if (is_header && buf->buf.bytesused != 0) {
+ if (is_header && buf->bytesused != 0) {
buf->state = UVC_BUF_STATE_DONE;
return -EAGAIN;
}
@@ -83,13 +83,13 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
* contain no data.
*/
if (!is_header) {
- maxlen = buf->buf.length - buf->buf.bytesused;
- mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+ maxlen = buf->length - buf->bytesused;
+ mem = buf->mem + buf->bytesused;
nbytes = min(len, maxlen);
memcpy(mem, data, nbytes);
- buf->buf.bytesused += nbytes;
+ buf->bytesused += nbytes;
- if (len > maxlen || buf->buf.bytesused == buf->buf.length) {
+ if (len > maxlen || buf->bytesused == buf->length) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete "
"(overflow).\n");
buf->state = UVC_BUF_STATE_DONE;
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index 677691c44500..8f54e24e3f35 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/atomic.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/list.h>
@@ -19,7 +20,7 @@
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
-#include <linux/atomic.h>
+#include <media/videobuf2-vmalloc.h>
#include "uvcvideo.h"
@@ -29,467 +30,211 @@
* Video queues is initialized by uvc_queue_init(). The function performs
* basic initialization of the uvc_video_queue struct and never fails.
*
- * Video buffer allocation and freeing are performed by uvc_alloc_buffers and
- * uvc_free_buffers respectively. The former acquires the video queue lock,
- * while the later must be called with the lock held (so that allocation can
- * free previously allocated buffers). Trying to free buffers that are mapped
- * to user space will return -EBUSY.
- *
- * Video buffers are managed using two queues. However, unlike most USB video
- * drivers that use an in queue and an out queue, we use a main queue to hold
- * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to
- * hold empty buffers. This design (copied from video-buf) minimizes locking
- * in interrupt, as only one queue is shared between interrupt and user
- * contexts.
- *
- * Use cases
- * ---------
- *
- * Unless stated otherwise, all operations that modify the irq buffers queue
- * are protected by the irq spinlock.
- *
- * 1. The user queues the buffers, starts streaming and dequeues a buffer.
- *
- * The buffers are added to the main and irq queues. Both operations are
- * protected by the queue lock, and the later is protected by the irq
- * spinlock as well.
- *
- * The completion handler fetches a buffer from the irq queue and fills it
- * with video data. If no buffer is available (irq queue empty), the handler
- * returns immediately.
- *
- * When the buffer is full, the completion handler removes it from the irq
- * queue, marks it as done (UVC_BUF_STATE_DONE) and wakes its wait queue.
- * At that point, any process waiting on the buffer will be woken up. If a
- * process tries to dequeue a buffer after it has been marked done, the
- * dequeing will succeed immediately.
- *
- * 2. Buffers are queued, user is waiting on a buffer and the device gets
- * disconnected.
- *
- * When the device is disconnected, the kernel calls the completion handler
- * with an appropriate status code. The handler marks all buffers in the
- * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
- * that any process waiting on a buffer gets woken up.
- *
- * Waking up up the first buffer on the irq list is not enough, as the
- * process waiting on the buffer might restart the dequeue operation
- * immediately.
- *
+ * Video buffers are managed by videobuf2. The driver uses a mutex to protect
+ * the videobuf2 queue operations by serializing calls to videobuf2 and a
+ * spinlock to protect the IRQ queue that holds the buffers to be processed by
+ * the driver.
*/
-void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
- int drop_corrupted)
-{
- mutex_init(&queue->mutex);
- spin_lock_init(&queue->irqlock);
- INIT_LIST_HEAD(&queue->mainqueue);
- INIT_LIST_HEAD(&queue->irqqueue);
- queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
- queue->type = type;
-}
-
-/*
- * Free the video buffers.
- *
- * This function must be called with the queue lock held.
+/* -----------------------------------------------------------------------------
+ * videobuf2 queue operations
*/
-static int __uvc_free_buffers(struct uvc_video_queue *queue)
+
+static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- unsigned int i;
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
+ struct uvc_streaming *stream =
+ container_of(queue, struct uvc_streaming, queue);
- for (i = 0; i < queue->count; ++i) {
- if (queue->buffer[i].vma_use_count != 0)
- return -EBUSY;
- }
+ if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
+ *nbuffers = UVC_MAX_VIDEO_BUFFERS;
- if (queue->count) {
- uvc_queue_cancel(queue, 0);
- INIT_LIST_HEAD(&queue->mainqueue);
- vfree(queue->mem);
- queue->count = 0;
- }
+ *nplanes = 1;
+
+ sizes[0] = stream->ctrl.dwMaxVideoFrameSize;
return 0;
}
-int uvc_free_buffers(struct uvc_video_queue *queue)
+static int uvc_buffer_prepare(struct vb2_buffer *vb)
{
- int ret;
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+ struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
- mutex_lock(&queue->mutex);
- ret = __uvc_free_buffers(queue);
- mutex_unlock(&queue->mutex);
+ if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
+ return -EINVAL;
+ }
- return ret;
-}
+ if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
+ return -ENODEV;
-/*
- * Allocate the video buffers.
- *
- * Pages are reserved to make sure they will not be swapped, as they will be
- * filled in the URB completion handler.
- *
- * Buffers will be individually mapped, so they must all be page aligned.
- */
-int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
- unsigned int buflength)
-{
- unsigned int bufsize = PAGE_ALIGN(buflength);
- unsigned int i;
- void *mem = NULL;
- int ret;
+ buf->state = UVC_BUF_STATE_QUEUED;
+ buf->error = 0;
+ buf->mem = vb2_plane_vaddr(vb, 0);
+ buf->length = vb2_plane_size(vb, 0);
+ if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ buf->bytesused = 0;
+ else
+ buf->bytesused = vb2_get_plane_payload(vb, 0);
- if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
- nbuffers = UVC_MAX_VIDEO_BUFFERS;
+ return 0;
+}
- mutex_lock(&queue->mutex);
+static void uvc_buffer_queue(struct vb2_buffer *vb)
+{
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+ struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
+ unsigned long flags;
- if ((ret = __uvc_free_buffers(queue)) < 0)
- goto done;
+ spin_lock_irqsave(&queue->irqlock, flags);
+ if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
+ list_add_tail(&buf->queue, &queue->irqqueue);
+ } else {
+ /* If the device is disconnected return the buffer to userspace
+ * directly. The next QBUF call will fail with -ENODEV.
+ */
+ buf->state = UVC_BUF_STATE_ERROR;
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
+ }
- /* Bail out if no buffers should be allocated. */
- if (nbuffers == 0)
- goto done;
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+}
- /* Decrement the number of buffers until allocation succeeds. */
- for (; nbuffers > 0; --nbuffers) {
- mem = vmalloc_32(nbuffers * bufsize);
- if (mem != NULL)
- break;
- }
+static int uvc_buffer_finish(struct vb2_buffer *vb)
+{
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+ struct uvc_streaming *stream =
+ container_of(queue, struct uvc_streaming, queue);
+ struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
- if (mem == NULL) {
- ret = -ENOMEM;
- goto done;
- }
+ uvc_video_clock_update(stream, &vb->v4l2_buf, buf);
+ return 0;
+}
- for (i = 0; i < nbuffers; ++i) {
- memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
- queue->buffer[i].buf.index = i;
- queue->buffer[i].buf.m.offset = i * bufsize;
- queue->buffer[i].buf.length = buflength;
- queue->buffer[i].buf.type = queue->type;
- queue->buffer[i].buf.field = V4L2_FIELD_NONE;
- queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
- queue->buffer[i].buf.flags = 0;
- init_waitqueue_head(&queue->buffer[i].wait);
- }
+static struct vb2_ops uvc_queue_qops = {
+ .queue_setup = uvc_queue_setup,
+ .buf_prepare = uvc_buffer_prepare,
+ .buf_queue = uvc_buffer_queue,
+ .buf_finish = uvc_buffer_finish,
+};
- queue->mem = mem;
- queue->count = nbuffers;
- queue->buf_size = bufsize;
- ret = nbuffers;
+void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
+ int drop_corrupted)
+{
+ queue->queue.type = type;
+ queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
+ queue->queue.drv_priv = queue;
+ queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
+ queue->queue.ops = &uvc_queue_qops;
+ queue->queue.mem_ops = &vb2_vmalloc_memops;
+ vb2_queue_init(&queue->queue);
-done:
- mutex_unlock(&queue->mutex);
- return ret;
+ mutex_init(&queue->mutex);
+ spin_lock_init(&queue->irqlock);
+ INIT_LIST_HEAD(&queue->irqqueue);
+ queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
}
-/*
- * Check if buffers have been allocated.
+/* -----------------------------------------------------------------------------
+ * V4L2 queue operations
*/
-int uvc_queue_allocated(struct uvc_video_queue *queue)
+
+int uvc_alloc_buffers(struct uvc_video_queue *queue,
+ struct v4l2_requestbuffers *rb)
{
- int allocated;
+ int ret;
mutex_lock(&queue->mutex);
- allocated = queue->count != 0;
+ ret = vb2_reqbufs(&queue->queue, rb);
mutex_unlock(&queue->mutex);
- return allocated;
+ return ret ? ret : rb->count;
}
-static void __uvc_query_buffer(struct uvc_buffer *buf,
- struct v4l2_buffer *v4l2_buf)
+void uvc_free_buffers(struct uvc_video_queue *queue)
{
- memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
-
- if (buf->vma_use_count)
- v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
-
- switch (buf->state) {
- case UVC_BUF_STATE_ERROR:
- case UVC_BUF_STATE_DONE:
- v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
- break;
- case UVC_BUF_STATE_QUEUED:
- case UVC_BUF_STATE_ACTIVE:
- case UVC_BUF_STATE_READY:
- v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
- break;
- case UVC_BUF_STATE_IDLE:
- default:
- break;
- }
+ mutex_lock(&queue->mutex);
+ vb2_queue_release(&queue->queue);
+ mutex_unlock(&queue->mutex);
}
-int uvc_query_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf)
+int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
{
- int ret = 0;
+ int ret;
mutex_lock(&queue->mutex);
- if (v4l2_buf->index >= queue->count) {
- ret = -EINVAL;
- goto done;
- }
-
- __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
-
-done:
+ ret = vb2_querybuf(&queue->queue, buf);
mutex_unlock(&queue->mutex);
+
return ret;
}
-/*
- * Queue a video buffer. Attempting to queue a buffer that has already been
- * queued will return -EINVAL.
- */
-int uvc_queue_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf)
+int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
{
- struct uvc_buffer *buf;
- unsigned long flags;
- int ret = 0;
-
- uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
-
- if (v4l2_buf->type != queue->type ||
- v4l2_buf->memory != V4L2_MEMORY_MMAP) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
- "and/or memory (%u).\n", v4l2_buf->type,
- v4l2_buf->memory);
- return -EINVAL;
- }
+ int ret;
mutex_lock(&queue->mutex);
- if (v4l2_buf->index >= queue->count) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
- ret = -EINVAL;
- goto done;
- }
-
- buf = &queue->buffer[v4l2_buf->index];
- if (buf->state != UVC_BUF_STATE_IDLE) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
- "(%u).\n", buf->state);
- ret = -EINVAL;
- goto done;
- }
-
- if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- v4l2_buf->bytesused > buf->buf.length) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
- ret = -EINVAL;
- goto done;
- }
-
- spin_lock_irqsave(&queue->irqlock, flags);
- if (queue->flags & UVC_QUEUE_DISCONNECTED) {
- spin_unlock_irqrestore(&queue->irqlock, flags);
- ret = -ENODEV;
- goto done;
- }
- buf->state = UVC_BUF_STATE_QUEUED;
- if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- buf->buf.bytesused = 0;
- else
- buf->buf.bytesused = v4l2_buf->bytesused;
-
- list_add_tail(&buf->stream, &queue->mainqueue);
- list_add_tail(&buf->queue, &queue->irqqueue);
- spin_unlock_irqrestore(&queue->irqlock, flags);
-
-done:
+ ret = vb2_qbuf(&queue->queue, buf);
mutex_unlock(&queue->mutex);
- return ret;
-}
-static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
-{
- if (nonblocking) {
- return (buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE &&
- buf->state != UVC_BUF_STATE_READY)
- ? 0 : -EAGAIN;
- }
-
- return wait_event_interruptible(buf->wait,
- buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE &&
- buf->state != UVC_BUF_STATE_READY);
+ return ret;
}
-/*
- * Dequeue a video buffer. If nonblocking is false, block until a buffer is
- * available.
- */
-int uvc_dequeue_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf, int nonblocking)
+int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
+ int nonblocking)
{
- struct uvc_buffer *buf;
- int ret = 0;
-
- if (v4l2_buf->type != queue->type ||
- v4l2_buf->memory != V4L2_MEMORY_MMAP) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
- "and/or memory (%u).\n", v4l2_buf->type,
- v4l2_buf->memory);
- return -EINVAL;
- }
+ int ret;
mutex_lock(&queue->mutex);
- if (list_empty(&queue->mainqueue)) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
- ret = -EINVAL;
- goto done;
- }
-
- buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
- if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
- goto done;
-
- uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
- buf->buf.index, buf->state, buf->buf.bytesused);
-
- switch (buf->state) {
- case UVC_BUF_STATE_ERROR:
- uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
- "(transmission error).\n");
- ret = -EIO;
- case UVC_BUF_STATE_DONE:
- buf->state = UVC_BUF_STATE_IDLE;
- break;
-
- case UVC_BUF_STATE_IDLE:
- case UVC_BUF_STATE_QUEUED:
- case UVC_BUF_STATE_ACTIVE:
- case UVC_BUF_STATE_READY:
- default:
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
- "(driver bug?).\n", buf->state);
- ret = -EINVAL;
- goto done;
- }
-
- list_del(&buf->stream);
- __uvc_query_buffer(buf, v4l2_buf);
-
-done:
+ ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
mutex_unlock(&queue->mutex);
- return ret;
-}
-/*
- * VMA operations.
- */
-static void uvc_vm_open(struct vm_area_struct *vma)
-{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count++;
-}
-
-static void uvc_vm_close(struct vm_area_struct *vma)
-{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count--;
+ return ret;
}
-static const struct vm_operations_struct uvc_vm_ops = {
- .open = uvc_vm_open,
- .close = uvc_vm_close,
-};
-
-/*
- * Memory-map a video buffer.
- *
- * This function implements video buffers memory mapping and is intended to be
- * used by the device mmap handler.
- */
int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
{
- struct uvc_buffer *uninitialized_var(buffer);
- struct page *page;
- unsigned long addr, start, size;
- unsigned int i;
- int ret = 0;
-
- start = vma->vm_start;
- size = vma->vm_end - vma->vm_start;
+ int ret;
mutex_lock(&queue->mutex);
+ ret = vb2_mmap(&queue->queue, vma);
+ mutex_unlock(&queue->mutex);
- for (i = 0; i < queue->count; ++i) {
- buffer = &queue->buffer[i];
- if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
-
- if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) {
- ret = -EINVAL;
- goto done;
- }
-
- /*
- * VM_IO marks the area as being an mmaped region for I/O to a
- * device. It also prevents the region from being core dumped.
- */
- vma->vm_flags |= VM_IO;
-
- addr = (unsigned long)queue->mem + buffer->buf.m.offset;
-#ifdef CONFIG_MMU
- while (size > 0) {
- page = vmalloc_to_page((void *)addr);
- if ((ret = vm_insert_page(vma, start, page)) < 0)
- goto done;
-
- start += PAGE_SIZE;
- addr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-#endif
+ return ret;
+}
- vma->vm_ops = &uvc_vm_ops;
- vma->vm_private_data = buffer;
- uvc_vm_open(vma);
+unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
+ poll_table *wait)
+{
+ unsigned int ret;
-done:
+ mutex_lock(&queue->mutex);
+ ret = vb2_poll(&queue->queue, file, wait);
mutex_unlock(&queue->mutex);
+
return ret;
}
-/*
- * Poll the video queue.
+/* -----------------------------------------------------------------------------
*
- * This function implements video queue polling and is intended to be used by
- * the device poll handler.
*/
-unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
- poll_table *wait)
+
+/*
+ * Check if buffers have been allocated.
+ */
+int uvc_queue_allocated(struct uvc_video_queue *queue)
{
- struct uvc_buffer *buf;
- unsigned int mask = 0;
+ int allocated;
mutex_lock(&queue->mutex);
- if (list_empty(&queue->mainqueue)) {
- mask |= POLLERR;
- goto done;
- }
- buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
-
- poll_wait(file, &buf->wait, wait);
- if (buf->state == UVC_BUF_STATE_DONE ||
- buf->state == UVC_BUF_STATE_ERROR) {
- if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- mask |= POLLIN | POLLRDNORM;
- else
- mask |= POLLOUT | POLLWRNORM;
- }
-
-done:
+ allocated = vb2_is_busy(&queue->queue);
mutex_unlock(&queue->mutex);
- return mask;
+
+ return allocated;
}
#ifndef CONFIG_MMU
@@ -515,7 +260,7 @@ unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
ret = -EINVAL;
goto done;
}
- ret = (unsigned long)queue->mem + buffer->buf.m.offset;
+ ret = (unsigned long)buf->mem;
done:
mutex_unlock(&queue->mutex);
return ret;
@@ -540,27 +285,24 @@ done:
*/
int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
{
- unsigned int i;
- int ret = 0;
+ unsigned long flags;
+ int ret;
mutex_lock(&queue->mutex);
if (enable) {
- if (uvc_queue_streaming(queue)) {
- ret = -EBUSY;
+ ret = vb2_streamon(&queue->queue, queue->queue.type);
+ if (ret < 0)
goto done;
- }
- queue->flags |= UVC_QUEUE_STREAMING;
+
queue->buf_used = 0;
} else {
- uvc_queue_cancel(queue, 0);
- INIT_LIST_HEAD(&queue->mainqueue);
-
- for (i = 0; i < queue->count; ++i) {
- queue->buffer[i].error = 0;
- queue->buffer[i].state = UVC_BUF_STATE_IDLE;
- }
+ ret = vb2_streamoff(&queue->queue, queue->queue.type);
+ if (ret < 0)
+ goto done;
- queue->flags &= ~UVC_QUEUE_STREAMING;
+ spin_lock_irqsave(&queue->irqlock, flags);
+ INIT_LIST_HEAD(&queue->irqqueue);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
}
done:
@@ -591,12 +333,12 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
queue);
list_del(&buf->queue);
buf->state = UVC_BUF_STATE_ERROR;
- wake_up(&buf->wait);
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
}
/* This must be protected by the irqlock spinlock to avoid race
- * conditions between uvc_queue_buffer and the disconnection event that
+ * conditions between uvc_buffer_queue and the disconnection event that
* could result in an interruptible wait in uvc_dequeue_buffer. Do not
- * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
+ * blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED
* state outside the queue code.
*/
if (disconnect)
@@ -613,14 +355,12 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
buf->error = 0;
buf->state = UVC_BUF_STATE_QUEUED;
- buf->buf.bytesused = 0;
+ vb2_set_plane_payload(&buf->buf, 0, 0);
return buf;
}
spin_lock_irqsave(&queue->irqlock, flags);
list_del(&buf->queue);
- buf->error = 0;
- buf->state = UVC_BUF_STATE_DONE;
if (!list_empty(&queue->irqqueue))
nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
queue);
@@ -628,7 +368,9 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
nextbuf = NULL;
spin_unlock_irqrestore(&queue->irqlock, flags);
- wake_up(&buf->wait);
+ buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
+ vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
+
return nextbuf;
}
-
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index dadf11f704dc..ff2cdddf9bc6 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/list.h>
@@ -58,6 +59,15 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
break;
case V4L2_CTRL_TYPE_MENU:
+ /* Prevent excessive memory consumption, as well as integer
+ * overflows.
+ */
+ if (xmap->menu_count == 0 ||
+ xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) {
+ ret = -EINVAL;
+ goto done;
+ }
+
size = xmap->menu_count * sizeof(*map->menu_info);
map->menu_info = kmalloc(size, GFP_KERNEL);
if (map->menu_info == NULL) {
@@ -513,10 +523,7 @@ static int uvc_v4l2_release(struct file *file)
/* Only free resources if this is a privileged handle. */
if (uvc_has_privileges(handle)) {
uvc_video_enable(stream, 0);
-
- if (uvc_free_buffers(&stream->queue) < 0)
- uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
- "free buffers.\n");
+ uvc_free_buffers(&stream->queue);
}
/* Release the file handle. */
@@ -914,19 +921,11 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* Buffers & streaming */
case VIDIOC_REQBUFS:
- {
- struct v4l2_requestbuffers *rb = arg;
-
- if (rb->type != stream->type ||
- rb->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
mutex_lock(&stream->mutex);
- ret = uvc_alloc_buffers(&stream->queue, rb->count,
- stream->ctrl.dwMaxVideoFrameSize);
+ ret = uvc_alloc_buffers(&stream->queue, arg);
mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
@@ -934,18 +933,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (ret == 0)
uvc_dismiss_privileges(handle);
- rb->count = ret;
ret = 0;
break;
- }
case VIDIOC_QUERYBUF:
{
struct v4l2_buffer *buf = arg;
- if (buf->type != stream->type)
- return -EINVAL;
-
if (!uvc_has_privileges(handle))
return -EBUSY;
@@ -1019,7 +1013,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
default:
uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd);
- return -EINVAL;
+ return -ENOTTY;
}
return ret;
@@ -1037,6 +1031,207 @@ static long uvc_v4l2_ioctl(struct file *file,
return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
}
+#ifdef CONFIG_COMPAT
+struct uvc_xu_control_mapping32 {
+ __u32 id;
+ __u8 name[32];
+ __u8 entity[16];
+ __u8 selector;
+
+ __u8 size;
+ __u8 offset;
+ __u32 v4l2_type;
+ __u32 data_type;
+
+ compat_caddr_t menu_info;
+ __u32 menu_count;
+
+ __u32 reserved[4];
+};
+
+static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp,
+ const struct uvc_xu_control_mapping32 __user *up)
+{
+ struct uvc_menu_info __user *umenus;
+ struct uvc_menu_info __user *kmenus;
+ compat_caddr_t p;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ __copy_from_user(kp, up, offsetof(typeof(*up), menu_info)) ||
+ __get_user(kp->menu_count, &up->menu_count))
+ return -EFAULT;
+
+ memset(kp->reserved, 0, sizeof(kp->reserved));
+
+ if (kp->menu_count == 0) {
+ kp->menu_info = NULL;
+ return 0;
+ }
+
+ if (__get_user(p, &up->menu_info))
+ return -EFAULT;
+ umenus = compat_ptr(p);
+ if (!access_ok(VERIFY_READ, umenus, kp->menu_count * sizeof(*umenus)))
+ return -EFAULT;
+
+ kmenus = compat_alloc_user_space(kp->menu_count * sizeof(*kmenus));
+ if (kmenus == NULL)
+ return -EFAULT;
+ kp->menu_info = kmenus;
+
+ if (copy_in_user(kmenus, umenus, kp->menu_count * sizeof(*umenus)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
+ struct uvc_xu_control_mapping32 __user *up)
+{
+ struct uvc_menu_info __user *umenus;
+ struct uvc_menu_info __user *kmenus = kp->menu_info;
+ compat_caddr_t p;
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) ||
+ __put_user(kp->menu_count, &up->menu_count))
+ return -EFAULT;
+
+ __clear_user(up->reserved, sizeof(up->reserved));
+
+ if (kp->menu_count == 0)
+ return 0;
+
+ if (get_user(p, &up->menu_info))
+ return -EFAULT;
+ umenus = compat_ptr(p);
+ if (!access_ok(VERIFY_WRITE, umenus, kp->menu_count * sizeof(*umenus)))
+ return -EFAULT;
+
+ if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus)))
+ return -EFAULT;
+
+ return 0;
+}
+
+struct uvc_xu_control_query32 {
+ __u8 unit;
+ __u8 selector;
+ __u8 query;
+ __u16 size;
+ compat_caddr_t data;
+};
+
+static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp,
+ const struct uvc_xu_control_query32 __user *up)
+{
+ u8 __user *udata;
+ u8 __user *kdata;
+ compat_caddr_t p;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+ __copy_from_user(kp, up, offsetof(typeof(*up), data)))
+ return -EFAULT;
+
+ if (kp->size == 0) {
+ kp->data = NULL;
+ return 0;
+ }
+
+ if (__get_user(p, &up->data))
+ return -EFAULT;
+ udata = compat_ptr(p);
+ if (!access_ok(VERIFY_READ, udata, kp->size))
+ return -EFAULT;
+
+ kdata = compat_alloc_user_space(kp->size);
+ if (kdata == NULL)
+ return -EFAULT;
+ kp->data = kdata;
+
+ if (copy_in_user(kdata, udata, kp->size))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp,
+ struct uvc_xu_control_query32 __user *up)
+{
+ u8 __user *udata;
+ u8 __user *kdata = kp->data;
+ compat_caddr_t p;
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ __copy_to_user(up, kp, offsetof(typeof(*up), data)))
+ return -EFAULT;
+
+ if (kp->size == 0)
+ return 0;
+
+ if (get_user(p, &up->data))
+ return -EFAULT;
+ udata = compat_ptr(p);
+ if (!access_ok(VERIFY_READ, udata, kp->size))
+ return -EFAULT;
+
+ if (copy_in_user(udata, kdata, kp->size))
+ return -EFAULT;
+
+ return 0;
+}
+
+#define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32)
+#define UVCIOC_CTRL_QUERY32 _IOWR('u', 0x21, struct uvc_xu_control_query32)
+
+static long uvc_v4l2_compat_ioctl32(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ union {
+ struct uvc_xu_control_mapping xmap;
+ struct uvc_xu_control_query xqry;
+ } karg;
+ void __user *up = compat_ptr(arg);
+ mm_segment_t old_fs;
+ long ret;
+
+ switch (cmd) {
+ case UVCIOC_CTRL_MAP32:
+ cmd = UVCIOC_CTRL_MAP;
+ ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up);
+ break;
+
+ case UVCIOC_CTRL_QUERY32:
+ cmd = UVCIOC_CTRL_QUERY;
+ ret = uvc_v4l2_get_xu_query(&karg.xqry, up);
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = uvc_v4l2_ioctl(file, cmd, (unsigned long)&karg);
+ set_fs(old_fs);
+
+ if (ret < 0)
+ return ret;
+
+ switch (cmd) {
+ case UVCIOC_CTRL_MAP:
+ ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
+ break;
+
+ case UVCIOC_CTRL_QUERY:
+ ret = uvc_v4l2_put_xu_query(&karg.xqry, up);
+ break;
+ }
+
+ return ret;
+}
+#endif
+
static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
@@ -1083,6 +1278,9 @@ const struct v4l2_file_operations uvc_fops = {
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
.unlocked_ioctl = uvc_v4l2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = uvc_v4l2_compat_ioctl32,
+#endif
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index b015e8e5e8b0..b76b0ac0958f 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -351,25 +351,565 @@ done:
return ret;
}
-int uvc_commit_video(struct uvc_streaming *stream,
- struct uvc_streaming_control *probe)
+static int uvc_commit_video(struct uvc_streaming *stream,
+ struct uvc_streaming_control *probe)
{
return uvc_set_video_ctrl(stream, probe, 0);
}
+/* -----------------------------------------------------------------------------
+ * Clocks and timestamps
+ */
+
+static void
+uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
+ const __u8 *data, int len)
+{
+ struct uvc_clock_sample *sample;
+ unsigned int header_size;
+ bool has_pts = false;
+ bool has_scr = false;
+ unsigned long flags;
+ struct timespec ts;
+ u16 host_sof;
+ u16 dev_sof;
+
+ switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
+ case UVC_STREAM_PTS | UVC_STREAM_SCR:
+ header_size = 12;
+ has_pts = true;
+ has_scr = true;
+ break;
+ case UVC_STREAM_PTS:
+ header_size = 6;
+ has_pts = true;
+ break;
+ case UVC_STREAM_SCR:
+ header_size = 8;
+ has_scr = true;
+ break;
+ default:
+ header_size = 2;
+ break;
+ }
+
+ /* Check for invalid headers. */
+ if (len < header_size)
+ return;
+
+ /* Extract the timestamps:
+ *
+ * - store the frame PTS in the buffer structure
+ * - if the SCR field is present, retrieve the host SOF counter and
+ * kernel timestamps and store them with the SCR STC and SOF fields
+ * in the ring buffer
+ */
+ if (has_pts && buf != NULL)
+ buf->pts = get_unaligned_le32(&data[2]);
+
+ if (!has_scr)
+ return;
+
+ /* To limit the amount of data, drop SCRs with an SOF identical to the
+ * previous one.
+ */
+ dev_sof = get_unaligned_le16(&data[header_size - 2]);
+ if (dev_sof == stream->clock.last_sof)
+ return;
+
+ stream->clock.last_sof = dev_sof;
+
+ host_sof = usb_get_current_frame_number(stream->dev->udev);
+ ktime_get_ts(&ts);
+
+ /* The UVC specification allows device implementations that can't obtain
+ * the USB frame number to keep their own frame counters as long as they
+ * match the size and frequency of the frame number associated with USB
+ * SOF tokens. The SOF values sent by such devices differ from the USB
+ * SOF tokens by a fixed offset that needs to be estimated and accounted
+ * for to make timestamp recovery as accurate as possible.
+ *
+ * The offset is estimated the first time a device SOF value is received
+ * as the difference between the host and device SOF values. As the two
+ * SOF values can differ slightly due to transmission delays, consider
+ * that the offset is null if the difference is not higher than 10 ms
+ * (negative differences can not happen and are thus considered as an
+ * offset). The video commit control wDelay field should be used to
+ * compute a dynamic threshold instead of using a fixed 10 ms value, but
+ * devices don't report reliable wDelay values.
+ *
+ * See uvc_video_clock_host_sof() for an explanation regarding why only
+ * the 8 LSBs of the delta are kept.
+ */
+ if (stream->clock.sof_offset == (u16)-1) {
+ u16 delta_sof = (host_sof - dev_sof) & 255;
+ if (delta_sof >= 10)
+ stream->clock.sof_offset = delta_sof;
+ else
+ stream->clock.sof_offset = 0;
+ }
+
+ dev_sof = (dev_sof + stream->clock.sof_offset) & 2047;
+
+ spin_lock_irqsave(&stream->clock.lock, flags);
+
+ sample = &stream->clock.samples[stream->clock.head];
+ sample->dev_stc = get_unaligned_le32(&data[header_size - 6]);
+ sample->dev_sof = dev_sof;
+ sample->host_sof = host_sof;
+ sample->host_ts = ts;
+
+ /* Update the sliding window head and count. */
+ stream->clock.head = (stream->clock.head + 1) % stream->clock.size;
+
+ if (stream->clock.count < stream->clock.size)
+ stream->clock.count++;
+
+ spin_unlock_irqrestore(&stream->clock.lock, flags);
+}
+
+static void uvc_video_clock_reset(struct uvc_streaming *stream)
+{
+ struct uvc_clock *clock = &stream->clock;
+
+ clock->head = 0;
+ clock->count = 0;
+ clock->last_sof = -1;
+ clock->sof_offset = -1;
+}
+
+static int uvc_video_clock_init(struct uvc_streaming *stream)
+{
+ struct uvc_clock *clock = &stream->clock;
+
+ spin_lock_init(&clock->lock);
+ clock->size = 32;
+
+ clock->samples = kmalloc(clock->size * sizeof(*clock->samples),
+ GFP_KERNEL);
+ if (clock->samples == NULL)
+ return -ENOMEM;
+
+ uvc_video_clock_reset(stream);
+
+ return 0;
+}
+
+static void uvc_video_clock_cleanup(struct uvc_streaming *stream)
+{
+ kfree(stream->clock.samples);
+ stream->clock.samples = NULL;
+}
+
+/*
+ * uvc_video_clock_host_sof - Return the host SOF value for a clock sample
+ *
+ * Host SOF counters reported by usb_get_current_frame_number() usually don't
+ * cover the whole 11-bits SOF range (0-2047) but are limited to the HCI frame
+ * schedule window. They can be limited to 8, 9 or 10 bits depending on the host
+ * controller and its configuration.
+ *
+ * We thus need to recover the SOF value corresponding to the host frame number.
+ * As the device and host frame numbers are sampled in a short interval, the
+ * difference between their values should be equal to a small delta plus an
+ * integer multiple of 256 caused by the host frame number limited precision.
+ *
+ * To obtain the recovered host SOF value, compute the small delta by masking
+ * the high bits of the host frame counter and device SOF difference and add it
+ * to the device SOF value.
+ */
+static u16 uvc_video_clock_host_sof(const struct uvc_clock_sample *sample)
+{
+ /* The delta value can be negative. */
+ s8 delta_sof;
+
+ delta_sof = (sample->host_sof - sample->dev_sof) & 255;
+
+ return (sample->dev_sof + delta_sof) & 2047;
+}
+
+/*
+ * uvc_video_clock_update - Update the buffer timestamp
+ *
+ * This function converts the buffer PTS timestamp to the host clock domain by
+ * going through the USB SOF clock domain and stores the result in the V4L2
+ * buffer timestamp field.
+ *
+ * The relationship between the device clock and the host clock isn't known.
+ * However, the device and the host share the common USB SOF clock which can be
+ * used to recover that relationship.
+ *
+ * The relationship between the device clock and the USB SOF clock is considered
+ * to be linear over the clock samples sliding window and is given by
+ *
+ * SOF = m * PTS + p
+ *
+ * Several methods to compute the slope (m) and intercept (p) can be used. As
+ * the clock drift should be small compared to the sliding window size, we
+ * assume that the line that goes through the points at both ends of the window
+ * is a good approximation. Naming those points P1 and P2, we get
+ *
+ * SOF = (SOF2 - SOF1) / (STC2 - STC1) * PTS
+ * + (SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1)
+ *
+ * or
+ *
+ * SOF = ((SOF2 - SOF1) * PTS + SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1) (1)
+ *
+ * to avoid loosing precision in the division. Similarly, the host timestamp is
+ * computed with
+ *
+ * TS = ((TS2 - TS1) * PTS + TS1 * SOF2 - TS2 * SOF1) / (SOF2 - SOF1) (2)
+ *
+ * SOF values are coded on 11 bits by USB. We extend their precision with 16
+ * decimal bits, leading to a 11.16 coding.
+ *
+ * TODO: To avoid surprises with device clock values, PTS/STC timestamps should
+ * be normalized using the nominal device clock frequency reported through the
+ * UVC descriptors.
+ *
+ * Both the PTS/STC and SOF counters roll over, after a fixed but device
+ * specific amount of time for PTS/STC and after 2048ms for SOF. As long as the
+ * sliding window size is smaller than the rollover period, differences computed
+ * on unsigned integers will produce the correct result. However, the p term in
+ * the linear relations will be miscomputed.
+ *
+ * To fix the issue, we subtract a constant from the PTS and STC values to bring
+ * PTS to half the 32 bit STC range. The sliding window STC values then fit into
+ * the 32 bit range without any rollover.
+ *
+ * Similarly, we add 2048 to the device SOF values to make sure that the SOF
+ * computed by (1) will never be smaller than 0. This offset is then compensated
+ * by adding 2048 to the SOF values used in (2). However, this doesn't prevent
+ * rollovers between (1) and (2): the SOF value computed by (1) can be slightly
+ * lower than 4096, and the host SOF counters can have rolled over to 2048. This
+ * case is handled by subtracting 2048 from the SOF value if it exceeds the host
+ * SOF value at the end of the sliding window.
+ *
+ * Finally we subtract a constant from the host timestamps to bring the first
+ * timestamp of the sliding window to 1s.
+ */
+void uvc_video_clock_update(struct uvc_streaming *stream,
+ struct v4l2_buffer *v4l2_buf,
+ struct uvc_buffer *buf)
+{
+ struct uvc_clock *clock = &stream->clock;
+ struct uvc_clock_sample *first;
+ struct uvc_clock_sample *last;
+ unsigned long flags;
+ struct timespec ts;
+ u32 delta_stc;
+ u32 y1, y2;
+ u32 x1, x2;
+ u32 mean;
+ u32 sof;
+ u32 div;
+ u32 rem;
+ u64 y;
+
+ spin_lock_irqsave(&clock->lock, flags);
+
+ if (clock->count < clock->size)
+ goto done;
+
+ first = &clock->samples[clock->head];
+ last = &clock->samples[(clock->head - 1) % clock->size];
+
+ /* First step, PTS to SOF conversion. */
+ delta_stc = buf->pts - (1UL << 31);
+ x1 = first->dev_stc - delta_stc;
+ x2 = last->dev_stc - delta_stc;
+ if (x1 == x2)
+ goto done;
+
+ y1 = (first->dev_sof + 2048) << 16;
+ y2 = (last->dev_sof + 2048) << 16;
+ if (y2 < y1)
+ y2 += 2048 << 16;
+
+ y = (u64)(y2 - y1) * (1ULL << 31) + (u64)y1 * (u64)x2
+ - (u64)y2 * (u64)x1;
+ y = div_u64(y, x2 - x1);
+
+ sof = y;
+
+ uvc_trace(UVC_TRACE_CLOCK, "%s: PTS %u y %llu.%06llu SOF %u.%06llu "
+ "(x1 %u x2 %u y1 %u y2 %u SOF offset %u)\n",
+ stream->dev->name, buf->pts,
+ y >> 16, div_u64((y & 0xffff) * 1000000, 65536),
+ sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
+ x1, x2, y1, y2, clock->sof_offset);
+
+ /* Second step, SOF to host clock conversion. */
+ x1 = (uvc_video_clock_host_sof(first) + 2048) << 16;
+ x2 = (uvc_video_clock_host_sof(last) + 2048) << 16;
+ if (x2 < x1)
+ x2 += 2048 << 16;
+ if (x1 == x2)
+ goto done;
+
+ ts = timespec_sub(last->host_ts, first->host_ts);
+ y1 = NSEC_PER_SEC;
+ y2 = (ts.tv_sec + 1) * NSEC_PER_SEC + ts.tv_nsec;
+
+ /* Interpolated and host SOF timestamps can wrap around at slightly
+ * different times. Handle this by adding or removing 2048 to or from
+ * the computed SOF value to keep it close to the SOF samples mean
+ * value.
+ */
+ mean = (x1 + x2) / 2;
+ if (mean - (1024 << 16) > sof)
+ sof += 2048 << 16;
+ else if (sof > mean + (1024 << 16))
+ sof -= 2048 << 16;
+
+ y = (u64)(y2 - y1) * (u64)sof + (u64)y1 * (u64)x2
+ - (u64)y2 * (u64)x1;
+ y = div_u64(y, x2 - x1);
+
+ div = div_u64_rem(y, NSEC_PER_SEC, &rem);
+ ts.tv_sec = first->host_ts.tv_sec - 1 + div;
+ ts.tv_nsec = first->host_ts.tv_nsec + rem;
+ if (ts.tv_nsec >= NSEC_PER_SEC) {
+ ts.tv_sec++;
+ ts.tv_nsec -= NSEC_PER_SEC;
+ }
+
+ uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %lu.%06lu "
+ "buf ts %lu.%06lu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n",
+ stream->dev->name,
+ sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
+ y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC,
+ v4l2_buf->timestamp.tv_sec, v4l2_buf->timestamp.tv_usec,
+ x1, first->host_sof, first->dev_sof,
+ x2, last->host_sof, last->dev_sof, y1, y2);
+
+ /* Update the V4L2 buffer. */
+ v4l2_buf->timestamp.tv_sec = ts.tv_sec;
+ v4l2_buf->timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+
+done:
+ spin_unlock_irqrestore(&stream->clock.lock, flags);
+}
+
/* ------------------------------------------------------------------------
- * Video codecs
+ * Stream statistics
*/
-/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
-#define UVC_STREAM_EOH (1 << 7)
-#define UVC_STREAM_ERR (1 << 6)
-#define UVC_STREAM_STI (1 << 5)
-#define UVC_STREAM_RES (1 << 4)
-#define UVC_STREAM_SCR (1 << 3)
-#define UVC_STREAM_PTS (1 << 2)
-#define UVC_STREAM_EOF (1 << 1)
-#define UVC_STREAM_FID (1 << 0)
+static void uvc_video_stats_decode(struct uvc_streaming *stream,
+ const __u8 *data, int len)
+{
+ unsigned int header_size;
+ bool has_pts = false;
+ bool has_scr = false;
+ u16 uninitialized_var(scr_sof);
+ u32 uninitialized_var(scr_stc);
+ u32 uninitialized_var(pts);
+
+ if (stream->stats.stream.nb_frames == 0 &&
+ stream->stats.frame.nb_packets == 0)
+ ktime_get_ts(&stream->stats.stream.start_ts);
+
+ switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
+ case UVC_STREAM_PTS | UVC_STREAM_SCR:
+ header_size = 12;
+ has_pts = true;
+ has_scr = true;
+ break;
+ case UVC_STREAM_PTS:
+ header_size = 6;
+ has_pts = true;
+ break;
+ case UVC_STREAM_SCR:
+ header_size = 8;
+ has_scr = true;
+ break;
+ default:
+ header_size = 2;
+ break;
+ }
+
+ /* Check for invalid headers. */
+ if (len < header_size || data[0] < header_size) {
+ stream->stats.frame.nb_invalid++;
+ return;
+ }
+
+ /* Extract the timestamps. */
+ if (has_pts)
+ pts = get_unaligned_le32(&data[2]);
+
+ if (has_scr) {
+ scr_stc = get_unaligned_le32(&data[header_size - 6]);
+ scr_sof = get_unaligned_le16(&data[header_size - 2]);
+ }
+
+ /* Is PTS constant through the whole frame ? */
+ if (has_pts && stream->stats.frame.nb_pts) {
+ if (stream->stats.frame.pts != pts) {
+ stream->stats.frame.nb_pts_diffs++;
+ stream->stats.frame.last_pts_diff =
+ stream->stats.frame.nb_packets;
+ }
+ }
+
+ if (has_pts) {
+ stream->stats.frame.nb_pts++;
+ stream->stats.frame.pts = pts;
+ }
+
+ /* Do all frames have a PTS in their first non-empty packet, or before
+ * their first empty packet ?
+ */
+ if (stream->stats.frame.size == 0) {
+ if (len > header_size)
+ stream->stats.frame.has_initial_pts = has_pts;
+ if (len == header_size && has_pts)
+ stream->stats.frame.has_early_pts = true;
+ }
+
+ /* Do the SCR.STC and SCR.SOF fields vary through the frame ? */
+ if (has_scr && stream->stats.frame.nb_scr) {
+ if (stream->stats.frame.scr_stc != scr_stc)
+ stream->stats.frame.nb_scr_diffs++;
+ }
+
+ if (has_scr) {
+ /* Expand the SOF counter to 32 bits and store its value. */
+ if (stream->stats.stream.nb_frames > 0 ||
+ stream->stats.frame.nb_scr > 0)
+ stream->stats.stream.scr_sof_count +=
+ (scr_sof - stream->stats.stream.scr_sof) % 2048;
+ stream->stats.stream.scr_sof = scr_sof;
+
+ stream->stats.frame.nb_scr++;
+ stream->stats.frame.scr_stc = scr_stc;
+ stream->stats.frame.scr_sof = scr_sof;
+
+ if (scr_sof < stream->stats.stream.min_sof)
+ stream->stats.stream.min_sof = scr_sof;
+ if (scr_sof > stream->stats.stream.max_sof)
+ stream->stats.stream.max_sof = scr_sof;
+ }
+
+ /* Record the first non-empty packet number. */
+ if (stream->stats.frame.size == 0 && len > header_size)
+ stream->stats.frame.first_data = stream->stats.frame.nb_packets;
+
+ /* Update the frame size. */
+ stream->stats.frame.size += len - header_size;
+
+ /* Update the packets counters. */
+ stream->stats.frame.nb_packets++;
+ if (len > header_size)
+ stream->stats.frame.nb_empty++;
+
+ if (data[1] & UVC_STREAM_ERR)
+ stream->stats.frame.nb_errors++;
+}
+
+static void uvc_video_stats_update(struct uvc_streaming *stream)
+{
+ struct uvc_stats_frame *frame = &stream->stats.frame;
+
+ uvc_trace(UVC_TRACE_STATS, "frame %u stats: %u/%u/%u packets, "
+ "%u/%u/%u pts (%searly %sinitial), %u/%u scr, "
+ "last pts/stc/sof %u/%u/%u\n",
+ stream->sequence, frame->first_data,
+ frame->nb_packets - frame->nb_empty, frame->nb_packets,
+ frame->nb_pts_diffs, frame->last_pts_diff, frame->nb_pts,
+ frame->has_early_pts ? "" : "!",
+ frame->has_initial_pts ? "" : "!",
+ frame->nb_scr_diffs, frame->nb_scr,
+ frame->pts, frame->scr_stc, frame->scr_sof);
+
+ stream->stats.stream.nb_frames++;
+ stream->stats.stream.nb_packets += stream->stats.frame.nb_packets;
+ stream->stats.stream.nb_empty += stream->stats.frame.nb_empty;
+ stream->stats.stream.nb_errors += stream->stats.frame.nb_errors;
+ stream->stats.stream.nb_invalid += stream->stats.frame.nb_invalid;
+
+ if (frame->has_early_pts)
+ stream->stats.stream.nb_pts_early++;
+ if (frame->has_initial_pts)
+ stream->stats.stream.nb_pts_initial++;
+ if (frame->last_pts_diff <= frame->first_data)
+ stream->stats.stream.nb_pts_constant++;
+ if (frame->nb_scr >= frame->nb_packets - frame->nb_empty)
+ stream->stats.stream.nb_scr_count_ok++;
+ if (frame->nb_scr_diffs + 1 == frame->nb_scr)
+ stream->stats.stream.nb_scr_diffs_ok++;
+
+ memset(&stream->stats.frame, 0, sizeof(stream->stats.frame));
+}
+
+size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
+ size_t size)
+{
+ unsigned int scr_sof_freq;
+ unsigned int duration;
+ struct timespec ts;
+ size_t count = 0;
+
+ ts.tv_sec = stream->stats.stream.stop_ts.tv_sec
+ - stream->stats.stream.start_ts.tv_sec;
+ ts.tv_nsec = stream->stats.stream.stop_ts.tv_nsec
+ - stream->stats.stream.start_ts.tv_nsec;
+ if (ts.tv_nsec < 0) {
+ ts.tv_sec--;
+ ts.tv_nsec += 1000000000;
+ }
+
+ /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF
+ * frequency this will not overflow before more than 1h.
+ */
+ duration = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+ if (duration != 0)
+ scr_sof_freq = stream->stats.stream.scr_sof_count * 1000
+ / duration;
+ else
+ scr_sof_freq = 0;
+
+ count += scnprintf(buf + count, size - count,
+ "frames: %u\npackets: %u\nempty: %u\n"
+ "errors: %u\ninvalid: %u\n",
+ stream->stats.stream.nb_frames,
+ stream->stats.stream.nb_packets,
+ stream->stats.stream.nb_empty,
+ stream->stats.stream.nb_errors,
+ stream->stats.stream.nb_invalid);
+ count += scnprintf(buf + count, size - count,
+ "pts: %u early, %u initial, %u ok\n",
+ stream->stats.stream.nb_pts_early,
+ stream->stats.stream.nb_pts_initial,
+ stream->stats.stream.nb_pts_constant);
+ count += scnprintf(buf + count, size - count,
+ "scr: %u count ok, %u diff ok\n",
+ stream->stats.stream.nb_scr_count_ok,
+ stream->stats.stream.nb_scr_diffs_ok);
+ count += scnprintf(buf + count, size - count,
+ "sof: %u <= sof <= %u, freq %u.%03u kHz\n",
+ stream->stats.stream.min_sof,
+ stream->stats.stream.max_sof,
+ scr_sof_freq / 1000, scr_sof_freq % 1000);
+
+ return count;
+}
+
+static void uvc_video_stats_start(struct uvc_streaming *stream)
+{
+ memset(&stream->stats, 0, sizeof(stream->stats));
+ stream->stats.stream.min_sof = 2048;
+}
+
+static void uvc_video_stats_stop(struct uvc_streaming *stream)
+{
+ ktime_get_ts(&stream->stats.stream.stop_ts);
+}
+
+/* ------------------------------------------------------------------------
+ * Video codecs
+ */
/* Video payload decoding is handled by uvc_video_decode_start(),
* uvc_video_decode_data() and uvc_video_decode_end().
@@ -416,14 +956,9 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
* - bHeaderLength value must be at least 2 bytes (see above)
* - bHeaderLength value can't be larger than the packet size.
*/
- if (len < 2 || data[0] < 2 || data[0] > len)
+ if (len < 2 || data[0] < 2 || data[0] > len) {
+ stream->stats.frame.nb_invalid++;
return -EINVAL;
-
- /* Skip payloads marked with the error bit ("error frames"). */
- if (data[1] & UVC_STREAM_ERR) {
- uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit "
- "set).\n");
- return -ENODATA;
}
fid = data[1] & UVC_STREAM_FID;
@@ -431,8 +966,14 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
/* Increase the sequence number regardless of any buffer states, so
* that discontinuous sequence numbers always indicate lost frames.
*/
- if (stream->last_fid != fid)
+ if (stream->last_fid != fid) {
stream->sequence++;
+ if (stream->sequence)
+ uvc_video_stats_update(stream);
+ }
+
+ uvc_video_clock_decode(stream, buf, data, len);
+ uvc_video_stats_decode(stream, data, len);
/* Store the payload FID bit and return immediately when the buffer is
* NULL.
@@ -442,6 +983,13 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
return -ENODATA;
}
+ /* Mark the buffer as bad if the error bit is set. */
+ if (data[1] & UVC_STREAM_ERR) {
+ uvc_trace(UVC_TRACE_FRAME, "Marking buffer as bad (error bit "
+ "set).\n");
+ buf->error = 1;
+ }
+
/* Synchronize to the input stream by waiting for the FID bit to be
* toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
* stream->last_fid is initialized to -1, so the first isochronous
@@ -467,9 +1015,10 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
else
ktime_get_real_ts(&ts);
- buf->buf.sequence = stream->sequence;
- buf->buf.timestamp.tv_sec = ts.tv_sec;
- buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+ buf->buf.v4l2_buf.sequence = stream->sequence;
+ buf->buf.v4l2_buf.timestamp.tv_sec = ts.tv_sec;
+ buf->buf.v4l2_buf.timestamp.tv_usec =
+ ts.tv_nsec / NSEC_PER_USEC;
/* TODO: Handle PTS and SCR. */
buf->state = UVC_BUF_STATE_ACTIVE;
@@ -490,7 +1039,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
* avoids detecting end of frame conditions at FID toggling if the
* previous payload had the EOF bit set.
*/
- if (fid != stream->last_fid && buf->buf.bytesused != 0) {
+ if (fid != stream->last_fid && buf->bytesused != 0) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
"toggled).\n");
buf->state = UVC_BUF_STATE_READY;
@@ -505,7 +1054,6 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
static void uvc_video_decode_data(struct uvc_streaming *stream,
struct uvc_buffer *buf, const __u8 *data, int len)
{
- struct uvc_video_queue *queue = &stream->queue;
unsigned int maxlen, nbytes;
void *mem;
@@ -513,11 +1061,11 @@ static void uvc_video_decode_data(struct uvc_streaming *stream,
return;
/* Copy the video data to the buffer. */
- maxlen = buf->buf.length - buf->buf.bytesused;
- mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+ maxlen = buf->length - buf->bytesused;
+ mem = buf->mem + buf->bytesused;
nbytes = min((unsigned int)len, maxlen);
memcpy(mem, data, nbytes);
- buf->buf.bytesused += nbytes;
+ buf->bytesused += nbytes;
/* Complete the current frame if the buffer size was exceeded. */
if (len > maxlen) {
@@ -530,7 +1078,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream,
struct uvc_buffer *buf, const __u8 *data, int len)
{
/* Mark the buffer as done if the EOF marker is set. */
- if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) {
+ if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
if (data[0] == len)
uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
@@ -568,8 +1116,8 @@ static int uvc_video_encode_data(struct uvc_streaming *stream,
void *mem;
/* Copy video data to the URB buffer. */
- mem = queue->mem + buf->buf.m.offset + queue->buf_used;
- nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
+ mem = buf->mem + queue->buf_used;
+ nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used);
nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size,
nbytes);
memcpy(data, mem, nbytes);
@@ -624,7 +1172,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
urb->iso_frame_desc[i].actual_length);
if (buf->state == UVC_BUF_STATE_READY) {
- if (buf->buf.length != buf->buf.bytesused &&
+ if (buf->length != buf->bytesused &&
!(stream->cur_format->flags &
UVC_FMT_FLAG_COMPRESSED))
buf->error = 1;
@@ -724,12 +1272,12 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
stream->bulk.payload_size += ret;
len -= ret;
- if (buf->buf.bytesused == stream->queue.buf_used ||
+ if (buf->bytesused == stream->queue.buf_used ||
stream->bulk.payload_size == stream->bulk.max_payload_size) {
- if (buf->buf.bytesused == stream->queue.buf_used) {
+ if (buf->bytesused == stream->queue.buf_used) {
stream->queue.buf_used = 0;
buf->state = UVC_BUF_STATE_READY;
- buf->buf.sequence = ++stream->sequence;
+ buf->buf.v4l2_buf.sequence = ++stream->sequence;
uvc_queue_next_buffer(&stream->queue, buf);
stream->last_fid ^= UVC_STREAM_FID;
}
@@ -870,6 +1418,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
struct urb *urb;
unsigned int i;
+ uvc_video_stats_stop(stream);
+
for (i = 0; i < UVC_URBS; ++i) {
urb = stream->urb[i];
if (urb == NULL)
@@ -1009,6 +1559,8 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
stream->bulk.skip_payload = 0;
stream->bulk.payload_size = 0;
+ uvc_video_stats_start(stream);
+
if (intf->num_altsetting > 1) {
struct usb_host_endpoint *best_ep = NULL;
unsigned int best_psize = 3 * 1024;
@@ -1133,6 +1685,8 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset)
stream->frozen = 0;
+ uvc_video_clock_reset(stream);
+
ret = uvc_commit_video(stream, &stream->ctrl);
if (ret < 0) {
uvc_queue_enable(&stream->queue, 0);
@@ -1269,20 +1823,35 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
uvc_uninit_video(stream, 1);
usb_set_interface(stream->dev->udev, stream->intfnum, 0);
uvc_queue_enable(&stream->queue, 0);
+ uvc_video_clock_cleanup(stream);
return 0;
}
- ret = uvc_queue_enable(&stream->queue, 1);
+ ret = uvc_video_clock_init(stream);
if (ret < 0)
return ret;
+ ret = uvc_queue_enable(&stream->queue, 1);
+ if (ret < 0)
+ goto error_queue;
+
/* Commit the streaming parameters. */
ret = uvc_commit_video(stream, &stream->ctrl);
- if (ret < 0) {
- uvc_queue_enable(&stream->queue, 0);
- return ret;
- }
+ if (ret < 0)
+ goto error_commit;
- return uvc_init_video(stream, GFP_KERNEL);
-}
+ ret = uvc_init_video(stream, GFP_KERNEL);
+ if (ret < 0)
+ goto error_video;
+ return 0;
+
+error_video:
+ usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+error_commit:
+ uvc_queue_enable(&stream->queue, 0);
+error_queue:
+ uvc_video_clock_cleanup(stream);
+
+ return ret;
+}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 4c1392ebcd4b..67f88d85bb16 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -13,6 +13,7 @@
#include <linux/videodev2.h>
#include <media/media-device.h>
#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
/* --------------------------------------------------------------------------
* UVC constants
@@ -113,6 +114,7 @@
/* Maximum allowed number of control mappings per device */
#define UVC_MAX_CONTROL_MAPPINGS 1024
+#define UVC_MAX_CONTROL_MENU_ENTRIES 32
/* Devices quirks */
#define UVC_QUIRK_STATUS_INTERVAL 0x00000001
@@ -319,35 +321,30 @@ enum uvc_buffer_state {
};
struct uvc_buffer {
- unsigned long vma_use_count;
- struct list_head stream;
-
- /* Touched by interrupt handler. */
- struct v4l2_buffer buf;
+ struct vb2_buffer buf;
struct list_head queue;
- wait_queue_head_t wait;
+
enum uvc_buffer_state state;
unsigned int error;
+
+ void *mem;
+ unsigned int length;
+ unsigned int bytesused;
+
+ u32 pts;
};
-#define UVC_QUEUE_STREAMING (1 << 0)
-#define UVC_QUEUE_DISCONNECTED (1 << 1)
-#define UVC_QUEUE_DROP_CORRUPTED (1 << 2)
+#define UVC_QUEUE_DISCONNECTED (1 << 0)
+#define UVC_QUEUE_DROP_CORRUPTED (1 << 1)
struct uvc_video_queue {
- enum v4l2_buf_type type;
+ struct vb2_queue queue;
+ struct mutex mutex; /* Protects queue */
- void *mem;
unsigned int flags;
-
- unsigned int count;
- unsigned int buf_size;
unsigned int buf_used;
- struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
- struct mutex mutex; /* protects buffers and mainqueue */
- spinlock_t irqlock; /* protects irqqueue */
- struct list_head mainqueue;
+ spinlock_t irqlock; /* Protects irqqueue */
struct list_head irqqueue;
};
@@ -362,6 +359,51 @@ struct uvc_video_chain {
struct mutex ctrl_mutex; /* Protects ctrl.info */
};
+struct uvc_stats_frame {
+ unsigned int size; /* Number of bytes captured */
+ unsigned int first_data; /* Index of the first non-empty packet */
+
+ unsigned int nb_packets; /* Number of packets */
+ unsigned int nb_empty; /* Number of empty packets */
+ unsigned int nb_invalid; /* Number of packets with an invalid header */
+ unsigned int nb_errors; /* Number of packets with the error bit set */
+
+ unsigned int nb_pts; /* Number of packets with a PTS timestamp */
+ unsigned int nb_pts_diffs; /* Number of PTS differences inside a frame */
+ unsigned int last_pts_diff; /* Index of the last PTS difference */
+ bool has_initial_pts; /* Whether the first non-empty packet has a PTS */
+ bool has_early_pts; /* Whether a PTS is present before the first non-empty packet */
+ u32 pts; /* PTS of the last packet */
+
+ unsigned int nb_scr; /* Number of packets with a SCR timestamp */
+ unsigned int nb_scr_diffs; /* Number of SCR.STC differences inside a frame */
+ u16 scr_sof; /* SCR.SOF of the last packet */
+ u32 scr_stc; /* SCR.STC of the last packet */
+};
+
+struct uvc_stats_stream {
+ struct timespec start_ts; /* Stream start timestamp */
+ struct timespec stop_ts; /* Stream stop timestamp */
+
+ unsigned int nb_frames; /* Number of frames */
+
+ unsigned int nb_packets; /* Number of packets */
+ unsigned int nb_empty; /* Number of empty packets */
+ unsigned int nb_invalid; /* Number of packets with an invalid header */
+ unsigned int nb_errors; /* Number of packets with the error bit set */
+
+ unsigned int nb_pts_constant; /* Number of frames with constant PTS */
+ unsigned int nb_pts_early; /* Number of frames with early PTS */
+ unsigned int nb_pts_initial; /* Number of frames with initial PTS */
+
+ unsigned int nb_scr_count_ok; /* Number of frames with at least one SCR per non empty packet */
+ unsigned int nb_scr_diffs_ok; /* Number of frames with varying SCR.STC */
+ unsigned int scr_sof_count; /* STC.SOF counter accumulated since stream start */
+ unsigned int scr_sof; /* STC.SOF of the last packet */
+ unsigned int min_sof; /* Minimum STC.SOF value */
+ unsigned int max_sof; /* Maximum STC.SOF value */
+};
+
struct uvc_streaming {
struct list_head list;
struct uvc_device *dev;
@@ -387,6 +429,7 @@ struct uvc_streaming {
*/
struct mutex mutex;
+ /* Buffers queue. */
unsigned int frozen : 1;
struct uvc_video_queue queue;
void (*decode) (struct urb *urb, struct uvc_streaming *video,
@@ -408,6 +451,32 @@ struct uvc_streaming {
__u32 sequence;
__u8 last_fid;
+
+ /* debugfs */
+ struct dentry *debugfs_dir;
+ struct {
+ struct uvc_stats_frame frame;
+ struct uvc_stats_stream stream;
+ } stats;
+
+ /* Timestamps support. */
+ struct uvc_clock {
+ struct uvc_clock_sample {
+ u32 dev_stc;
+ u16 dev_sof;
+ struct timespec host_ts;
+ u16 host_sof;
+ } *samples;
+
+ unsigned int head;
+ unsigned int count;
+ unsigned int size;
+
+ u16 last_sof;
+ u16 sof_offset;
+
+ spinlock_t lock;
+ } clock;
};
enum uvc_device_state {
@@ -479,9 +548,12 @@ struct uvc_driver {
#define UVC_TRACE_SUSPEND (1 << 8)
#define UVC_TRACE_STATUS (1 << 9)
#define UVC_TRACE_VIDEO (1 << 10)
+#define UVC_TRACE_STATS (1 << 11)
+#define UVC_TRACE_CLOCK (1 << 12)
#define UVC_WARN_MINMAX 0
#define UVC_WARN_PROBE_DEF 1
+#define UVC_WARN_XU_GET_RES 2
extern unsigned int uvc_clock_param;
extern unsigned int uvc_no_drop_param;
@@ -516,8 +588,8 @@ extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
extern void uvc_queue_init(struct uvc_video_queue *queue,
enum v4l2_buf_type type, int drop_corrupted);
extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
- unsigned int nbuffers, unsigned int buflength);
-extern int uvc_free_buffers(struct uvc_video_queue *queue);
+ struct v4l2_requestbuffers *rb);
+extern void uvc_free_buffers(struct uvc_video_queue *queue);
extern int uvc_query_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *v4l2_buf);
extern int uvc_queue_buffer(struct uvc_video_queue *queue,
@@ -539,7 +611,7 @@ extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
extern int uvc_queue_allocated(struct uvc_video_queue *queue);
static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
{
- return queue->flags & UVC_QUEUE_STREAMING;
+ return vb2_is_streaming(&queue->queue);
}
/* V4L2 interface */
@@ -556,10 +628,11 @@ extern int uvc_video_resume(struct uvc_streaming *stream, int reset);
extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
extern int uvc_probe_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe);
-extern int uvc_commit_video(struct uvc_streaming *stream,
- struct uvc_streaming_control *ctrl);
extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
__u8 intfnum, __u8 cs, void *data, __u16 size);
+void uvc_video_clock_update(struct uvc_streaming *stream,
+ struct v4l2_buffer *v4l2_buf,
+ struct uvc_buffer *buf);
/* Status */
extern int uvc_status_init(struct uvc_device *dev);
@@ -612,4 +685,13 @@ extern struct usb_host_endpoint *uvc_find_endpoint(
void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
struct uvc_buffer *buf);
+/* debugfs and statistics */
+int uvc_debugfs_init(void);
+void uvc_debugfs_cleanup(void);
+int uvc_debugfs_init_stream(struct uvc_streaming *stream);
+void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
+
+size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
+ size_t size);
+
#endif
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 5c6100fb4072..1baec8393306 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -55,7 +55,6 @@
#include <linux/spi/spi.h>
#endif
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/div64.h>
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index c68531b88279..2829d256e4b7 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -14,12 +14,11 @@
*/
#include <linux/compat.h>
-#include <linux/videodev2.h>
#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
-#ifdef CONFIG_COMPAT
-
static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret = -ENOIOCTLCMD;
@@ -937,6 +936,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
{
+ struct video_device *vdev = video_devdata(file);
long ret = -ENOIOCTLCMD;
if (!file->f_op->unlocked_ioctl)
@@ -985,6 +985,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_CROPCAP:
case VIDIOC_G_CROP:
case VIDIOC_S_CROP:
+ case VIDIOC_G_SELECTION:
+ case VIDIOC_S_SELECTION:
case VIDIOC_G_JPEGCOMP:
case VIDIOC_S_JPEGCOMP:
case VIDIOC_QUERYSTD:
@@ -1003,6 +1005,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_G_ENC_INDEX:
case VIDIOC_ENCODER_CMD:
case VIDIOC_TRY_ENCODER_CMD:
+ case VIDIOC_DECODER_CMD:
+ case VIDIOC_TRY_DECODER_CMD:
case VIDIOC_DBG_S_REGISTER:
case VIDIOC_DBG_G_REGISTER:
case VIDIOC_DBG_G_CHIP_IDENT:
@@ -1023,14 +1027,16 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
break;
default:
- printk(KERN_WARNING "compat_ioctl32: "
- "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
- _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
+ if (vdev->fops->compat_ioctl32)
+ ret = vdev->fops->compat_ioctl32(file, cmd, arg);
+
+ if (ret == -ENOIOCTLCMD)
+ printk(KERN_WARNING "compat_ioctl32: "
+ "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
+ _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd),
+ cmd);
break;
}
return ret;
}
EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
-#endif
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 0f415dade05a..18015c0a8d31 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -175,6 +175,15 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
"16-bit CRC",
NULL
};
+ static const char * const mpeg_audio_dec_playback[] = {
+ "Auto",
+ "Stereo",
+ "Left",
+ "Right",
+ "Mono",
+ "Swapped Stereo",
+ NULL
+ };
static const char * const mpeg_video_encoding[] = {
"MPEG-1",
"MPEG-2",
@@ -236,8 +245,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
};
static const char * const tune_preemphasis[] = {
"No Preemphasis",
- "50 useconds",
- "75 useconds",
+ "50 Microseconds",
+ "75 Microseconds",
NULL,
};
static const char * const header_mode[] = {
@@ -334,7 +343,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
};
static const char * const mpeg4_profile[] = {
"Simple",
- "Adcanved Simple",
+ "Advanced Simple",
"Core",
"Simple Scalable",
"Advanced Coding Efficency",
@@ -353,6 +362,16 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
NULL,
};
+ static const char * const jpeg_chroma_subsampling[] = {
+ "4:4:4",
+ "4:2:2",
+ "4:2:0",
+ "4:1:1",
+ "4:1:0",
+ "Gray",
+ NULL,
+ };
+
switch (id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
return mpeg_audio_sampling_freq;
@@ -374,6 +393,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
return mpeg_audio_emphasis;
case V4L2_CID_MPEG_AUDIO_CRC:
return mpeg_audio_crc;
+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
+ return mpeg_audio_dec_playback;
case V4L2_CID_MPEG_VIDEO_ENCODING:
return mpeg_video_encoding;
case V4L2_CID_MPEG_VIDEO_ASPECT:
@@ -414,6 +436,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
return mpeg_mpeg4_level;
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
return mpeg4_profile;
+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+ return jpeg_chroma_subsampling;
+
default:
return NULL;
}
@@ -465,8 +490,9 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_CHROMA_GAIN: return "Chroma Gain";
case V4L2_CID_ILLUMINATORS_1: return "Illuminator 1";
case V4L2_CID_ILLUMINATORS_2: return "Illuminator 2";
- case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: return "Minimum Number of Capture Buffers";
- case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Minimum Number of Output Buffers";
+ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: return "Min Number of Capture Buffers";
+ case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Min Number of Output Buffers";
+ case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component";
/* MPEG controls */
/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -491,6 +517,8 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: return "Audio Playback";
+ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback";
case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
@@ -505,25 +533,25 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";
case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: return "Decoder Slice Interface";
case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: return "MPEG4 Loop Filter Enable";
- case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "The Number of Intra Refresh MBs";
+ case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "Number of Intra Refresh MBs";
case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: return "Frame Level Rate Control Enable";
case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: return "H264 MB Level Rate Control";
case V4L2_CID_MPEG_VIDEO_HEADER_MODE: return "Sequence Header Mode";
- case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: return "The Max Number of Reference Picture";
+ case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: return "Max Number of Reference Pics";
case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: return "H263 I-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: return "H263 P frame QP Value";
- case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: return "H263 B frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: return "H263 P-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: return "H263 B-Frame QP Value";
case V4L2_CID_MPEG_VIDEO_H263_MIN_QP: return "H263 Minimum QP Value";
case V4L2_CID_MPEG_VIDEO_H263_MAX_QP: return "H263 Maximum QP Value";
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: return "H264 I-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: return "H264 P frame QP Value";
- case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: return "H264 B frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: return "H264 P-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: return "H264 B-Frame QP Value";
case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: return "H264 Maximum QP Value";
case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: return "H264 Minimum QP Value";
case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: return "H264 8x8 Transform Enable";
case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: return "H264 CPB Buffer Size";
- case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: return "H264 Entorpy Mode";
- case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: return "H264 I Period";
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: return "H264 Entropy Mode";
+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: return "H264 I-Frame Period";
case V4L2_CID_MPEG_VIDEO_H264_LEVEL: return "H264 Level";
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: return "H264 Loop Filter Alpha Offset";
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: return "H264 Loop Filter Beta Offset";
@@ -534,17 +562,19 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: return "Aspect Ratio VUI Enable";
case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return "VUI Aspect Ratio IDC";
case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P frame QP Value";
- case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value";
case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: return "MPEG4 Minimum QP Value";
case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: return "MPEG4 Maximum QP Value";
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return "MPEG4 Level";
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: return "MPEG4 Profile";
case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: return "Quarter Pixel Search Enable";
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: return "The Maximum Bytes Per Slice";
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "The Number of MB in a Slice";
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "The Slice Partitioning Method";
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: return "Maximum Bytes in a Slice";
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice";
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method";
case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size";
+ case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS";
+ case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count";
/* CAMERA controls */
/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -579,7 +609,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled";
case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation";
- case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled";
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Enabled";
case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain";
case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
@@ -587,24 +617,32 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled";
case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation";
case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency";
- case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-emphasis settings";
+ case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-Emphasis";
case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level";
case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor";
/* Flash controls */
- case V4L2_CID_FLASH_CLASS: return "Flash controls";
- case V4L2_CID_FLASH_LED_MODE: return "LED mode";
- case V4L2_CID_FLASH_STROBE_SOURCE: return "Strobe source";
+ case V4L2_CID_FLASH_CLASS: return "Flash Controls";
+ case V4L2_CID_FLASH_LED_MODE: return "LED Mode";
+ case V4L2_CID_FLASH_STROBE_SOURCE: return "Strobe Source";
case V4L2_CID_FLASH_STROBE: return "Strobe";
- case V4L2_CID_FLASH_STROBE_STOP: return "Stop strobe";
- case V4L2_CID_FLASH_STROBE_STATUS: return "Strobe status";
- case V4L2_CID_FLASH_TIMEOUT: return "Strobe timeout";
- case V4L2_CID_FLASH_INTENSITY: return "Intensity, flash mode";
- case V4L2_CID_FLASH_TORCH_INTENSITY: return "Intensity, torch mode";
- case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, indicator";
+ case V4L2_CID_FLASH_STROBE_STOP: return "Stop Strobe";
+ case V4L2_CID_FLASH_STROBE_STATUS: return "Strobe Status";
+ case V4L2_CID_FLASH_TIMEOUT: return "Strobe Timeout";
+ case V4L2_CID_FLASH_INTENSITY: return "Intensity, Flash Mode";
+ case V4L2_CID_FLASH_TORCH_INTENSITY: return "Intensity, Torch Mode";
+ case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, Indicator";
case V4L2_CID_FLASH_FAULT: return "Faults";
case V4L2_CID_FLASH_CHARGE: return "Charge";
- case V4L2_CID_FLASH_READY: return "Ready to strobe";
+ case V4L2_CID_FLASH_READY: return "Ready to Strobe";
+
+ /* JPEG encoder controls */
+ /* Keep the order of the 'case's the same as in videodev2.h! */
+ case V4L2_CID_JPEG_CLASS: return "JPEG Compression Controls";
+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: return "Chroma Subsampling";
+ case V4L2_CID_JPEG_RESTART_INTERVAL: return "Restart Interval";
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality";
+ case V4L2_CID_JPEG_ACTIVE_MARKER: return "Active Markers";
default:
return NULL;
@@ -673,6 +711,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
case V4L2_CID_MPEG_AUDIO_EMPHASIS:
case V4L2_CID_MPEG_AUDIO_CRC:
+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
case V4L2_CID_MPEG_VIDEO_ENCODING:
case V4L2_CID_MPEG_VIDEO_ASPECT:
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
@@ -692,6 +732,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
*type = V4L2_CTRL_TYPE_MENU;
break;
case V4L2_CID_RDS_TX_PS_NAME:
@@ -703,6 +744,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_CLASS:
case V4L2_CID_FM_TX_CLASS:
case V4L2_CID_FLASH_CLASS:
+ case V4L2_CID_JPEG_CLASS:
*type = V4L2_CTRL_TYPE_CTRL_CLASS;
/* You can neither read not write these */
*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -716,6 +758,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
*max = 0xFFFFFF;
break;
case V4L2_CID_FLASH_FAULT:
+ case V4L2_CID_JPEG_ACTIVE_MARKER:
*type = V4L2_CTRL_TYPE_BITMASK;
break;
case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
@@ -723,6 +766,11 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
*type = V4L2_CTRL_TYPE_INTEGER;
*flags |= V4L2_CTRL_FLAG_READ_ONLY;
break;
+ case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
+ case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+ *type = V4L2_CTRL_TYPE_INTEGER64;
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE;
+ break;
default:
*type = V4L2_CTRL_TYPE_INTEGER;
break;
@@ -1108,8 +1156,8 @@ int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
INIT_LIST_HEAD(&hdl->ctrls);
INIT_LIST_HEAD(&hdl->ctrl_refs);
hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
- hdl->buckets = kzalloc(sizeof(hdl->buckets[0]) * hdl->nr_of_buckets,
- GFP_KERNEL);
+ hdl->buckets = kcalloc(hdl->nr_of_buckets, sizeof(hdl->buckets[0]),
+ GFP_KERNEL);
hdl->error = hdl->buckets ? 0 : -ENOMEM;
return hdl->error;
}
@@ -1469,7 +1517,7 @@ EXPORT_SYMBOL(v4l2_ctrl_add_ctrl);
int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl_handler *add)
{
- struct v4l2_ctrl *ctrl;
+ struct v4l2_ctrl_ref *ref;
int ret = 0;
/* Do nothing if either handler is NULL or if they are the same */
@@ -1478,7 +1526,9 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
if (hdl->error)
return hdl->error;
mutex_lock(&add->lock);
- list_for_each_entry(ctrl, &add->ctrls, node) {
+ list_for_each_entry(ref, &add->ctrl_refs, node) {
+ struct v4l2_ctrl *ctrl = ref->ctrl;
+
/* Skip handler-private controls. */
if (ctrl->is_private)
continue;
@@ -2358,3 +2408,35 @@ void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
v4l2_ctrl_unlock(ctrl);
}
EXPORT_SYMBOL(v4l2_ctrl_del_event);
+
+int v4l2_ctrl_log_status(struct file *file, void *fh)
+{
+ struct video_device *vfd = video_devdata(file);
+ struct v4l2_fh *vfh = file->private_data;
+
+ if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev)
+ v4l2_ctrl_handler_log_status(vfh->ctrl_handler,
+ vfd->v4l2_dev->name);
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_log_status);
+
+int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ if (sub->type == V4L2_EVENT_CTRL)
+ return v4l2_event_subscribe(fh, sub, 0);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
+
+unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct v4l2_fh *fh = file->private_data;
+
+ if (v4l2_event_pending(fh))
+ return POLLPRI;
+ poll_wait(file, &fh->wait, wait);
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_poll);
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index a5c9ed128b97..70bec548d904 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -26,7 +26,6 @@
#include <linux/kmod.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
@@ -146,10 +145,9 @@ static void v4l2_device_release(struct device *cd)
struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
mutex_lock(&videodev_lock);
- if (video_device[vdev->minor] != vdev) {
- mutex_unlock(&videodev_lock);
+ if (WARN_ON(video_device[vdev->minor] != vdev)) {
/* should not happen */
- WARN_ON(1);
+ mutex_unlock(&videodev_lock);
return;
}
@@ -168,7 +166,7 @@ static void v4l2_device_release(struct device *cd)
mutex_unlock(&videodev_lock);
#if defined(CONFIG_MEDIA_CONTROLLER)
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+ if (v4l2_dev && v4l2_dev->mdev &&
vdev->vfl_type != VFL_TYPE_SUBDEV)
media_device_unregister_entity(&vdev->entity);
#endif
@@ -556,8 +554,7 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
vdev->minor = -1;
/* the release callback MUST be present */
- WARN_ON(!vdev->release);
- if (!vdev->release)
+ if (WARN_ON(!vdev->release))
return -EINVAL;
/* v4l2_fh support */
@@ -703,8 +700,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
vdev->vfl_type != VFL_TYPE_SUBDEV) {
vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
vdev->entity.name = vdev->name;
- vdev->entity.v4l.major = VIDEO_MAJOR;
- vdev->entity.v4l.minor = vdev->minor;
+ vdev->entity.info.v4l.major = VIDEO_MAJOR;
+ vdev->entity.info.v4l.minor = vdev->minor;
ret = media_device_register_entity(vdev->v4l2_dev->mdev,
&vdev->entity);
if (ret < 0)
@@ -790,7 +787,7 @@ static void __exit videodev_exit(void)
unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
}
-module_init(videodev_init)
+subsys_initcall(videodev_init);
module_exit(videodev_exit)
MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 0edd618b9ddf..1f203b85a637 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -234,8 +234,8 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
goto clean_up;
}
#if defined(CONFIG_MEDIA_CONTROLLER)
- sd->entity.v4l.major = VIDEO_MAJOR;
- sd->entity.v4l.minor = vdev->minor;
+ sd->entity.info.v4l.major = VIDEO_MAJOR;
+ sd->entity.info.v4l.minor = vdev->minor;
#endif
sd->devnode = vdev;
}
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index e1da8fc9dd2f..5b2ec1fd2d0a 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -238,6 +238,8 @@ static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP",
[_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP",
[_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP",
+ [_IOC_NR(VIDIOC_G_SELECTION)] = "VIDIOC_G_SELECTION",
+ [_IOC_NR(VIDIOC_S_SELECTION)] = "VIDIOC_S_SELECTION",
[_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP",
[_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP",
[_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD",
@@ -258,6 +260,8 @@ static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD",
[_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD",
+ [_IOC_NR(VIDIOC_DECODER_CMD)] = "VIDIOC_DECODER_CMD",
+ [_IOC_NR(VIDIOC_TRY_DECODER_CMD)] = "VIDIOC_TRY_DECODER_CMD",
[_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER",
[_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
@@ -538,10 +542,12 @@ static long __video_do_ioctl(struct file *file,
if (!ret)
dbgarg(cmd, "driver=%s, card=%s, bus=%s, "
"version=0x%08x, "
- "capabilities=0x%08x\n",
+ "capabilities=0x%08x, "
+ "device_caps=0x%08x\n",
cap->driver, cap->card, cap->bus_info,
cap->version,
- cap->capabilities);
+ cap->capabilities,
+ cap->device_caps);
break;
}
@@ -1547,11 +1553,32 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_crop *p = arg;
- if (!ops->vidioc_g_crop)
+ if (!ops->vidioc_g_crop && !ops->vidioc_g_selection)
break;
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
- ret = ops->vidioc_g_crop(file, fh, p);
+
+ if (ops->vidioc_g_crop) {
+ ret = ops->vidioc_g_crop(file, fh, p);
+ } else {
+ /* simulate capture crop using selection api */
+ struct v4l2_selection s = {
+ .type = p->type,
+ };
+
+ /* crop means compose for output devices */
+ if (V4L2_TYPE_IS_OUTPUT(p->type))
+ s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
+ else
+ s.target = V4L2_SEL_TGT_CROP_ACTIVE;
+
+ ret = ops->vidioc_g_selection(file, fh, &s);
+
+ /* copying results to old structure on success */
+ if (!ret)
+ p->c = s.r;
+ }
+
if (!ret)
dbgrect(vfd, "", &p->c);
break;
@@ -1560,15 +1587,65 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_crop *p = arg;
- if (!ops->vidioc_s_crop)
+ if (!ops->vidioc_s_crop && !ops->vidioc_s_selection)
break;
+
if (ret_prio) {
ret = ret_prio;
break;
}
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
dbgrect(vfd, "", &p->c);
- ret = ops->vidioc_s_crop(file, fh, p);
+
+ if (ops->vidioc_s_crop) {
+ ret = ops->vidioc_s_crop(file, fh, p);
+ } else {
+ /* simulate capture crop using selection api */
+ struct v4l2_selection s = {
+ .type = p->type,
+ .r = p->c,
+ };
+
+ /* crop means compose for output devices */
+ if (V4L2_TYPE_IS_OUTPUT(p->type))
+ s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
+ else
+ s.target = V4L2_SEL_TGT_CROP_ACTIVE;
+
+ ret = ops->vidioc_s_selection(file, fh, &s);
+ }
+ break;
+ }
+ case VIDIOC_G_SELECTION:
+ {
+ struct v4l2_selection *p = arg;
+
+ if (!ops->vidioc_g_selection)
+ break;
+
+ dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+
+ ret = ops->vidioc_g_selection(file, fh, p);
+ if (!ret)
+ dbgrect(vfd, "", &p->r);
+ break;
+ }
+ case VIDIOC_S_SELECTION:
+ {
+ struct v4l2_selection *p = arg;
+
+ if (!ops->vidioc_s_selection)
+ break;
+
+ if (ret_prio) {
+ ret = ret_prio;
+ break;
+ }
+
+ dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+ dbgrect(vfd, "", &p->r);
+
+ ret = ops->vidioc_s_selection(file, fh, p);
break;
}
case VIDIOC_CROPCAP:
@@ -1576,11 +1653,42 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_cropcap *p = arg;
/*FIXME: Should also show v4l2_fract pixelaspect */
- if (!ops->vidioc_cropcap)
+ if (!ops->vidioc_cropcap && !ops->vidioc_g_selection)
break;
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
- ret = ops->vidioc_cropcap(file, fh, p);
+ if (ops->vidioc_cropcap) {
+ ret = ops->vidioc_cropcap(file, fh, p);
+ } else {
+ struct v4l2_selection s = { .type = p->type };
+
+ /* obtaining bounds */
+ if (V4L2_TYPE_IS_OUTPUT(p->type))
+ s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS;
+ else
+ s.target = V4L2_SEL_TGT_CROP_BOUNDS;
+
+ ret = ops->vidioc_g_selection(file, fh, &s);
+ if (ret)
+ break;
+ p->bounds = s.r;
+
+ /* obtaining defrect */
+ if (V4L2_TYPE_IS_OUTPUT(p->type))
+ s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
+ else
+ s.target = V4L2_SEL_TGT_CROP_DEFAULT;
+
+ ret = ops->vidioc_g_selection(file, fh, &s);
+ if (ret)
+ break;
+ p->defrect = s.r;
+
+ /* setting trivial pixelaspect */
+ p->pixelaspect.numerator = 1;
+ p->pixelaspect.denominator = 1;
+ }
+
if (!ret) {
dbgrect(vfd, "bounds ", &p->bounds);
dbgrect(vfd, "defrect ", &p->defrect);
@@ -1658,6 +1766,32 @@ static long __video_do_ioctl(struct file *file,
dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
break;
}
+ case VIDIOC_DECODER_CMD:
+ {
+ struct v4l2_decoder_cmd *p = arg;
+
+ if (!ops->vidioc_decoder_cmd)
+ break;
+ if (ret_prio) {
+ ret = ret_prio;
+ break;
+ }
+ ret = ops->vidioc_decoder_cmd(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+ break;
+ }
+ case VIDIOC_TRY_DECODER_CMD:
+ {
+ struct v4l2_decoder_cmd *p = arg;
+
+ if (!ops->vidioc_try_decoder_cmd)
+ break;
+ ret = ops->vidioc_try_decoder_cmd(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+ break;
+ }
case VIDIOC_G_PARM:
{
struct v4l2_streamparm *p = arg;
@@ -1767,6 +1901,7 @@ static long __video_do_ioctl(struct file *file,
case VIDIOC_S_FREQUENCY:
{
struct v4l2_frequency *p = arg;
+ enum v4l2_tuner_type type;
if (!ops->vidioc_s_frequency)
break;
@@ -1774,9 +1909,14 @@ static long __video_do_ioctl(struct file *file,
ret = ret_prio;
break;
}
+ type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+ V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
p->tuner, p->type, p->frequency);
- ret = ops->vidioc_s_frequency(file, fh, p);
+ if (p->type != type)
+ ret = -EINVAL;
+ else
+ ret = ops->vidioc_s_frequency(file, fh, p);
break;
}
case VIDIOC_G_SLICED_VBI_CAP:
@@ -1799,7 +1939,13 @@ static long __video_do_ioctl(struct file *file,
{
if (!ops->vidioc_log_status)
break;
+ if (vfd->v4l2_dev)
+ pr_info("%s: ================= START STATUS =================\n",
+ vfd->v4l2_dev->name);
ret = ops->vidioc_log_status(file, fh);
+ if (vfd->v4l2_dev)
+ pr_info("%s: ================== END STATUS ==================\n",
+ vfd->v4l2_dev->name);
break;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -2226,6 +2372,10 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
struct v4l2_ext_controls *ctrls = parg;
if (ctrls->count != 0) {
+ if (ctrls->count > V4L2_CID_MAX_CTRLS) {
+ ret = -EINVAL;
+ break;
+ }
*user_ptr = (void __user *)ctrls->controls;
*kernel_ptr = (void *)&ctrls->controls;
*array_size = sizeof(struct v4l2_ext_control)
@@ -2305,7 +2455,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
/* Handles IOCTL */
err = func(file, cmd, parg);
if (err == -ENOIOCTLCMD)
- err = -EINVAL;
+ err = -ENOTTY;
if (has_array_args) {
*kernel_ptr = user_ptr;
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 65ade5f03c2e..6fe88e965a8c 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -193,6 +193,18 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return v4l2_subdev_call(sd, core, s_register, p);
}
#endif
+
+ case VIDIOC_LOG_STATUS: {
+ int ret;
+
+ pr_info("%s: ================= START STATUS =================\n",
+ sd->name);
+ ret = v4l2_subdev_call(sd, core, log_status);
+ pr_info("%s: ================== END STATUS ==================\n",
+ sd->name);
+ return ret;
+ }
+
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
case VIDIOC_SUBDEV_G_FMT: {
struct v4l2_subdev_format *format = arg;
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index cbf13d09b4ac..20f7237b8242 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -34,13 +34,13 @@ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver");
MODULE_LICENSE("GPL");
-static int flip_image;
+static bool flip_image;
module_param(flip_image, bool, 0444);
MODULE_PARM_DESC(flip_image,
"If set, the sensor will be instructed to flip the image "
"vertically.");
-static int override_serial;
+static bool override_serial;
module_param(override_serial, bool, 0444);
MODULE_PARM_DESC(override_serial,
"The camera driver will normally refuse to load if "
@@ -156,14 +156,10 @@ static struct via_format {
.mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
.bpp = 2,
},
- {
- .desc = "RGB 565",
- .pixelformat = V4L2_PIX_FMT_RGB565,
- .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
- .bpp = 2,
- },
/* RGB444 and Bayer should be doable, but have never been
- tested with this driver. */
+ tested with this driver. RGB565 seems to work at the default
+ resolution, but results in color corruption when being scaled by
+ viacam_set_scaled(), and is disabled as a result. */
};
#define N_VIA_FMTS ARRAY_SIZE(via_formats)
@@ -1504,14 +1500,4 @@ static struct platform_driver viacam_driver = {
.remove = viacam_remove,
};
-static int viacam_init(void)
-{
- return platform_driver_register(&viacam_driver);
-}
-module_init(viacam_init);
-
-static void viacam_exit(void)
-{
- platform_driver_unregister(&viacam_driver);
-}
-module_exit(viacam_exit);
+module_platform_driver(viacam_driver);
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index 3de7c7e4402d..59cb54aa2946 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -226,9 +226,10 @@ static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter,
}
/* register network adapter */
- dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
- if (dvb->net.dvbdev == NULL) {
- result = -ENOMEM;
+ result = dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_net_init failed (errno = %d)\n",
+ dvb->name, result);
goto fail_fe_conn;
}
return 0;
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 95a3f5e82aef..2e8f1df775b6 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -30,7 +30,7 @@ module_param(debug, int, 0644);
printk(KERN_DEBUG "vb2: " fmt, ## arg); \
} while (0)
-#define call_memop(q, plane, op, args...) \
+#define call_memop(q, op, args...) \
(((q)->mem_ops->op) ? \
((q)->mem_ops->op(args)) : 0)
@@ -52,7 +52,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
/* Allocate memory for all planes in this buffer */
for (plane = 0; plane < vb->num_planes; ++plane) {
- mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane],
+ mem_priv = call_memop(q, alloc, q->alloc_ctx[plane],
q->plane_sizes[plane]);
if (IS_ERR_OR_NULL(mem_priv))
goto free;
@@ -65,8 +65,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
return 0;
free:
/* Free already allocated memory if one of the allocations failed */
- for (; plane > 0; --plane)
- call_memop(q, plane, put, vb->planes[plane - 1].mem_priv);
+ for (; plane > 0; --plane) {
+ call_memop(q, put, vb->planes[plane - 1].mem_priv);
+ vb->planes[plane - 1].mem_priv = NULL;
+ }
return -ENOMEM;
}
@@ -80,10 +82,10 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb)
unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane) {
- call_memop(q, plane, put, vb->planes[plane].mem_priv);
+ call_memop(q, put, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL;
- dprintk(3, "Freed plane %d of buffer %d\n",
- plane, vb->v4l2_buf.index);
+ dprintk(3, "Freed plane %d of buffer %d\n", plane,
+ vb->v4l2_buf.index);
}
}
@@ -97,12 +99,9 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane) {
- void *mem_priv = vb->planes[plane].mem_priv;
-
- if (mem_priv) {
- call_memop(q, plane, put_userptr, mem_priv);
- vb->planes[plane].mem_priv = NULL;
- }
+ if (vb->planes[plane].mem_priv)
+ call_memop(q, put_userptr, vb->planes[plane].mem_priv);
+ vb->planes[plane].mem_priv = NULL;
}
}
@@ -305,7 +304,7 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
* case anyway. If num_users() returns more than 1,
* we are not the only user of the plane's memory.
*/
- if (mem_priv && call_memop(q, plane, num_users, mem_priv) > 1)
+ if (mem_priv && call_memop(q, num_users, mem_priv) > 1)
return true;
}
return false;
@@ -731,10 +730,10 @@ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no)
{
struct vb2_queue *q = vb->vb2_queue;
- if (plane_no > vb->num_planes)
+ if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
return NULL;
- return call_memop(q, plane_no, vaddr, vb->planes[plane_no].mem_priv);
+ return call_memop(q, vaddr, vb->planes[plane_no].mem_priv);
}
EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
@@ -754,10 +753,10 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no)
{
struct vb2_queue *q = vb->vb2_queue;
- if (plane_no > vb->num_planes)
+ if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
return NULL;
- return call_memop(q, plane_no, cookie, vb->planes[plane_no].mem_priv);
+ return call_memop(q, cookie, vb->planes[plane_no].mem_priv);
}
EXPORT_SYMBOL_GPL(vb2_plane_cookie);
@@ -883,7 +882,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
for (plane = 0; plane < vb->num_planes; ++plane) {
/* Skip the plane if already verified */
- if (vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr
+ if (vb->v4l2_planes[plane].m.userptr &&
+ vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr
&& vb->v4l2_planes[plane].length == planes[plane].length)
continue;
@@ -898,27 +898,23 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
/* Release previously acquired memory if present */
if (vb->planes[plane].mem_priv)
- call_memop(q, plane, put_userptr,
- vb->planes[plane].mem_priv);
+ call_memop(q, put_userptr, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL;
vb->v4l2_planes[plane].m.userptr = 0;
vb->v4l2_planes[plane].length = 0;
/* Acquire each plane's memory */
- if (q->mem_ops->get_userptr) {
- mem_priv = q->mem_ops->get_userptr(q->alloc_ctx[plane],
- planes[plane].m.userptr,
- planes[plane].length,
- write);
- if (IS_ERR(mem_priv)) {
- dprintk(1, "qbuf: failed acquiring userspace "
+ mem_priv = call_memop(q, get_userptr, q->alloc_ctx[plane],
+ planes[plane].m.userptr,
+ planes[plane].length, write);
+ if (IS_ERR_OR_NULL(mem_priv)) {
+ dprintk(1, "qbuf: failed acquiring userspace "
"memory for plane %d\n", plane);
- ret = PTR_ERR(mem_priv);
- goto err;
- }
- vb->planes[plane].mem_priv = mem_priv;
+ ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL;
+ goto err;
}
+ vb->planes[plane].mem_priv = mem_priv;
}
/*
@@ -943,8 +939,7 @@ err:
/* In case of errors, release planes that were already acquired */
for (plane = 0; plane < vb->num_planes; ++plane) {
if (vb->planes[plane].mem_priv)
- call_memop(q, plane, put_userptr,
- vb->planes[plane].mem_priv);
+ call_memop(q, put_userptr, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL;
vb->v4l2_planes[plane].m.userptr = 0;
vb->v4l2_planes[plane].length = 0;
@@ -1081,46 +1076,76 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf);
*/
int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
{
+ struct rw_semaphore *mmap_sem = NULL;
struct vb2_buffer *vb;
- int ret;
+ int ret = 0;
+
+ /*
+ * In case of user pointer buffers vb2 allocator needs to get direct
+ * access to userspace pages. This requires getting read access on
+ * mmap semaphore in the current process structure. The same
+ * semaphore is taken before calling mmap operation, while both mmap
+ * and qbuf are called by the driver or v4l2 core with driver's lock
+ * held. To avoid a AB-BA deadlock (mmap_sem then driver's lock in
+ * mmap and driver's lock then mmap_sem in qbuf) the videobuf2 core
+ * release driver's lock, takes mmap_sem and then takes again driver's
+ * lock.
+ *
+ * To avoid race with other vb2 calls, which might be called after
+ * releasing driver's lock, this operation is performed at the
+ * beggining of qbuf processing. This way the queue status is
+ * consistent after getting driver's lock back.
+ */
+ if (q->memory == V4L2_MEMORY_USERPTR) {
+ mmap_sem = &current->mm->mmap_sem;
+ call_qop(q, wait_prepare, q);
+ down_read(mmap_sem);
+ call_qop(q, wait_finish, q);
+ }
if (q->fileio) {
dprintk(1, "qbuf: file io in progress\n");
- return -EBUSY;
+ ret = -EBUSY;
+ goto unlock;
}
if (b->type != q->type) {
dprintk(1, "qbuf: invalid buffer type\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto unlock;
}
if (b->index >= q->num_buffers) {
dprintk(1, "qbuf: buffer index out of range\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto unlock;
}
vb = q->bufs[b->index];
if (NULL == vb) {
/* Should never happen */
dprintk(1, "qbuf: buffer is NULL\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto unlock;
}
if (b->memory != q->memory) {
dprintk(1, "qbuf: invalid memory type\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto unlock;
}
switch (vb->state) {
case VB2_BUF_STATE_DEQUEUED:
ret = __buf_prepare(vb, b);
if (ret)
- return ret;
+ goto unlock;
case VB2_BUF_STATE_PREPARED:
break;
default:
dprintk(1, "qbuf: buffer already in use\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto unlock;
}
/*
@@ -1141,7 +1166,10 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
__fill_v4l2_buffer(vb, b);
dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index);
- return 0;
+unlock:
+ if (mmap_sem)
+ up_read(mmap_sem);
+ return ret;
}
EXPORT_SYMBOL_GPL(vb2_qbuf);
@@ -1521,7 +1549,6 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
{
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
- struct vb2_plane *vb_plane;
struct vb2_buffer *vb;
unsigned int buffer, plane;
int ret;
@@ -1558,9 +1585,8 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
return ret;
vb = q->bufs[buffer];
- vb_plane = &vb->planes[plane];
- ret = q->mem_ops->mmap(vb_plane->mem_priv, vma);
+ ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma);
if (ret)
return ret;
diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c
index 3bad8b105fea..25c3b360e1ad 100644
--- a/drivers/media/video/videobuf2-dma-sg.c
+++ b/drivers/media/video/videobuf2-dma-sg.c
@@ -140,7 +140,6 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
if (!buf->pages)
goto userptr_fail_pages_array_alloc;
- down_read(&current->mm->mmap_sem);
num_pages_from_user = get_user_pages(current, current->mm,
vaddr & PAGE_MASK,
buf->sg_desc.num_pages,
@@ -148,7 +147,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
1, /* force */
buf->pages,
NULL);
- up_read(&current->mm->mmap_sem);
+
if (num_pages_from_user != buf->sg_desc.num_pages)
goto userptr_fail_get_user_pages;
diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c
index 71a7a78c3fc0..c41cb60245d6 100644
--- a/drivers/media/video/videobuf2-memops.c
+++ b/drivers/media/video/videobuf2-memops.c
@@ -100,29 +100,26 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
unsigned long offset, start, end;
unsigned long this_pfn, prev_pfn;
dma_addr_t pa = 0;
- int ret = -EFAULT;
start = vaddr;
offset = start & ~PAGE_MASK;
end = start + size;
- down_read(&mm->mmap_sem);
vma = find_vma(mm, start);
if (vma == NULL || vma->vm_end < end)
- goto done;
+ return -EFAULT;
for (prev_pfn = 0; start < end; start += PAGE_SIZE) {
- ret = follow_pfn(vma, start, &this_pfn);
+ int ret = follow_pfn(vma, start, &this_pfn);
if (ret)
- goto done;
+ return ret;
if (prev_pfn == 0)
pa = this_pfn << PAGE_SHIFT;
- else if (this_pfn != prev_pfn + 1) {
- ret = -EFAULT;
- goto done;
- }
+ else if (this_pfn != prev_pfn + 1)
+ return -EFAULT;
+
prev_pfn = this_pfn;
}
@@ -130,16 +127,11 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
* Memory is contigous, lock vma and return to the caller
*/
*res_vma = vb2_get_vma(vma);
- if (*res_vma == NULL) {
- ret = -ENOMEM;
- goto done;
- }
- *res_pa = pa + offset;
- ret = 0;
+ if (*res_vma == NULL)
+ return -ENOMEM;
-done:
- up_read(&mm->mmap_sem);
- return ret;
+ *res_pa = pa + offset;
+ return 0;
}
EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c
index a3a884234059..6b5ca6c70a46 100644
--- a/drivers/media/video/videobuf2-vmalloc.c
+++ b/drivers/media/video/videobuf2-vmalloc.c
@@ -10,8 +10,10 @@
* the Free Software Foundation.
*/
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/mm.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -20,7 +22,11 @@
struct vb2_vmalloc_buf {
void *vaddr;
+ struct page **pages;
+ struct vm_area_struct *vma;
+ int write;
unsigned long size;
+ unsigned int n_pages;
atomic_t refcount;
struct vb2_vmarea_handler handler;
};
@@ -31,7 +37,7 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
{
struct vb2_vmalloc_buf *buf;
- buf = kzalloc(sizeof *buf, GFP_KERNEL);
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
return NULL;
@@ -42,15 +48,12 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
buf->handler.arg = buf;
if (!buf->vaddr) {
- printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size);
+ pr_debug("vmalloc of size %ld failed\n", buf->size);
kfree(buf);
return NULL;
}
atomic_inc(&buf->refcount);
- printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n",
- buf->size, buf->vaddr);
-
return buf;
}
@@ -59,21 +62,106 @@ static void vb2_vmalloc_put(void *buf_priv)
struct vb2_vmalloc_buf *buf = buf_priv;
if (atomic_dec_and_test(&buf->refcount)) {
- printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n",
- __func__, buf->vaddr);
vfree(buf->vaddr);
kfree(buf);
}
}
-static void *vb2_vmalloc_vaddr(void *buf_priv)
+static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
+ unsigned long size, int write)
+{
+ struct vb2_vmalloc_buf *buf;
+ unsigned long first, last;
+ int n_pages, offset;
+ struct vm_area_struct *vma;
+ dma_addr_t physp;
+
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ buf->write = write;
+ offset = vaddr & ~PAGE_MASK;
+ buf->size = size;
+
+
+ vma = find_vma(current->mm, vaddr);
+ if (vma && (vma->vm_flags & VM_PFNMAP) && (vma->vm_pgoff)) {
+ if (vb2_get_contig_userptr(vaddr, size, &vma, &physp))
+ goto fail_pages_array_alloc;
+ buf->vma = vma;
+ buf->vaddr = ioremap_nocache(physp, size);
+ if (!buf->vaddr)
+ goto fail_pages_array_alloc;
+ } else {
+ first = vaddr >> PAGE_SHIFT;
+ last = (vaddr + size - 1) >> PAGE_SHIFT;
+ buf->n_pages = last - first + 1;
+ buf->pages = kzalloc(buf->n_pages * sizeof(struct page *),
+ GFP_KERNEL);
+ if (!buf->pages)
+ goto fail_pages_array_alloc;
+
+ /* current->mm->mmap_sem is taken by videobuf2 core */
+ n_pages = get_user_pages(current, current->mm,
+ vaddr & PAGE_MASK, buf->n_pages,
+ write, 1, /* force */
+ buf->pages, NULL);
+ if (n_pages != buf->n_pages)
+ goto fail_get_user_pages;
+
+ buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1,
+ PAGE_KERNEL);
+ if (!buf->vaddr)
+ goto fail_get_user_pages;
+ }
+
+ buf->vaddr += offset;
+ return buf;
+
+fail_get_user_pages:
+ pr_debug("get_user_pages requested/got: %d/%d]\n", n_pages,
+ buf->n_pages);
+ while (--n_pages >= 0)
+ put_page(buf->pages[n_pages]);
+ kfree(buf->pages);
+
+fail_pages_array_alloc:
+ kfree(buf);
+
+ return NULL;
+}
+
+static void vb2_vmalloc_put_userptr(void *buf_priv)
{
struct vb2_vmalloc_buf *buf = buf_priv;
+ unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
+ unsigned int i;
+
+ if (buf->pages) {
+ if (vaddr)
+ vm_unmap_ram((void *)vaddr, buf->n_pages);
+ for (i = 0; i < buf->n_pages; ++i) {
+ if (buf->write)
+ set_page_dirty_lock(buf->pages[i]);
+ put_page(buf->pages[i]);
+ }
+ kfree(buf->pages);
+ } else {
+ if (buf->vma)
+ vb2_put_vma(buf->vma);
+ iounmap(buf->vaddr);
+ }
+ kfree(buf);
+}
- BUG_ON(!buf);
+static void *vb2_vmalloc_vaddr(void *buf_priv)
+{
+ struct vb2_vmalloc_buf *buf = buf_priv;
if (!buf->vaddr) {
- printk(KERN_ERR "Address of an unallocated plane requested\n");
+ pr_err("Address of an unallocated plane requested "
+ "or cannot map user pointer\n");
return NULL;
}
@@ -92,13 +180,13 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
int ret;
if (!buf) {
- printk(KERN_ERR "No memory to map\n");
+ pr_err("No memory to map\n");
return -EINVAL;
}
ret = remap_vmalloc_range(vma, buf->vaddr, 0);
if (ret) {
- printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret);
+ pr_err("Remapping vmalloc memory, error: %d\n", ret);
return ret;
}
@@ -121,6 +209,8 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
const struct vb2_mem_ops vb2_vmalloc_memops = {
.alloc = vb2_vmalloc_alloc,
.put = vb2_vmalloc_put,
+ .get_userptr = vb2_vmalloc_get_userptr,
+ .put_userptr = vb2_vmalloc_put_userptr,
.vaddr = vb2_vmalloc_vaddr,
.mmap = vb2_vmalloc_mmap,
.num_users = vb2_vmalloc_num_users,
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 52a0a3736c82..4d7391ec8001 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -708,7 +708,7 @@ static int vino_allocate_buffer(struct vino_framebuffer *fb,
size, count);
/* allocate memory for table with virtual (page) addresses */
- fb->desc_table.virtual = (unsigned long *)
+ fb->desc_table.virtual =
kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
if (!fb->desc_table.virtual)
return -ENOMEM;
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 7d754fbcccbf..5e8b0710105b 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -819,8 +819,9 @@ static int vidioc_querycap(struct file *file, void *priv,
strcpy(cap->driver, "vivi");
strcpy(cap->card, "vivi");
strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -958,14 +959,6 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
return vb2_streamoff(&dev->vb_vidq, i);
}
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct vivi_dev *dev = video_drvdata(file);
-
- v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name);
- return 0;
-}
-
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
{
return 0;
@@ -1008,17 +1001,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-static int vidioc_subscribe_event(struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub)
-{
- switch (sub->type) {
- case V4L2_EVENT_CTRL:
- return v4l2_event_subscribe(fh, sub, 0);
- default:
- return -EINVAL;
- }
-}
-
/* --- controls ---------------------------------------------- */
static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -1209,8 +1191,8 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_s_input = vidioc_s_input,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_subscribe_event = vidioc_subscribe_event,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
index c15efb6e7771..7cfbc9d94a48 100644
--- a/drivers/media/video/vp27smpx.c
+++ b/drivers/media/video/vp27smpx.c
@@ -208,15 +208,4 @@ static struct i2c_driver vp27smpx_driver = {
.id_table = vp27smpx_id,
};
-static __init int init_vp27smpx(void)
-{
- return i2c_add_driver(&vp27smpx_driver);
-}
-
-static __exit void exit_vp27smpx(void)
-{
- i2c_del_driver(&vp27smpx_driver);
-}
-
-module_init(init_vp27smpx);
-module_exit(exit_vp27smpx);
+module_i2c_driver(vp27smpx_driver);
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index e5cad6ff64a1..2f67b4c5c823 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -588,15 +588,4 @@ static struct i2c_driver vpx3220_driver = {
.id_table = vpx3220_id,
};
-static __init int init_vpx3220(void)
-{
- return i2c_add_driver(&vpx3220_driver);
-}
-
-static __exit void exit_vpx3220(void)
-{
- i2c_del_driver(&vpx3220_driver);
-}
-
-module_init(init_vpx3220);
-module_exit(exit_vpx3220);
+module_i2c_driver(vpx3220_driver);
diff --git a/drivers/media/video/vs6624.c b/drivers/media/video/vs6624.c
new file mode 100644
index 000000000000..42ae9dc9c574
--- /dev/null
+++ b/drivers/media/video/vs6624.c
@@ -0,0 +1,928 @@
+/*
+ * vs6624.c ST VS6624 CMOS image sensor driver
+ *
+ * Copyright (c) 2011 Analog Devices 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.
+ *
+ * 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/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+
+#include "vs6624_regs.h"
+
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 480
+#define QVGA_WIDTH 320
+#define QVGA_HEIGHT 240
+#define QQVGA_WIDTH 160
+#define QQVGA_HEIGHT 120
+#define CIF_WIDTH 352
+#define CIF_HEIGHT 288
+#define QCIF_WIDTH 176
+#define QCIF_HEIGHT 144
+#define QQCIF_WIDTH 88
+#define QQCIF_HEIGHT 72
+
+#define MAX_FRAME_RATE 30
+
+struct vs6624 {
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_fract frame_rate;
+ struct v4l2_mbus_framefmt fmt;
+ unsigned ce_pin;
+};
+
+static const struct vs6624_format {
+ enum v4l2_mbus_pixelcode mbus_code;
+ enum v4l2_colorspace colorspace;
+} vs6624_formats[] = {
+ {
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ },
+};
+
+static struct v4l2_mbus_framefmt vs6624_default_fmt = {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+};
+
+static const u16 vs6624_p1[] = {
+ 0x8104, 0x03,
+ 0x8105, 0x01,
+ 0xc900, 0x03,
+ 0xc904, 0x47,
+ 0xc905, 0x10,
+ 0xc906, 0x80,
+ 0xc907, 0x3a,
+ 0x903a, 0x02,
+ 0x903b, 0x47,
+ 0x903c, 0x15,
+ 0xc908, 0x31,
+ 0xc909, 0xdc,
+ 0xc90a, 0x80,
+ 0xc90b, 0x44,
+ 0x9044, 0x02,
+ 0x9045, 0x31,
+ 0x9046, 0xe2,
+ 0xc90c, 0x07,
+ 0xc90d, 0xe0,
+ 0xc90e, 0x80,
+ 0xc90f, 0x47,
+ 0x9047, 0x90,
+ 0x9048, 0x83,
+ 0x9049, 0x81,
+ 0x904a, 0xe0,
+ 0x904b, 0x60,
+ 0x904c, 0x08,
+ 0x904d, 0x90,
+ 0x904e, 0xc0,
+ 0x904f, 0x43,
+ 0x9050, 0x74,
+ 0x9051, 0x01,
+ 0x9052, 0xf0,
+ 0x9053, 0x80,
+ 0x9054, 0x05,
+ 0x9055, 0xE4,
+ 0x9056, 0x90,
+ 0x9057, 0xc0,
+ 0x9058, 0x43,
+ 0x9059, 0xf0,
+ 0x905a, 0x02,
+ 0x905b, 0x07,
+ 0x905c, 0xec,
+ 0xc910, 0x5d,
+ 0xc911, 0xca,
+ 0xc912, 0x80,
+ 0xc913, 0x5d,
+ 0x905d, 0xa3,
+ 0x905e, 0x04,
+ 0x905f, 0xf0,
+ 0x9060, 0xa3,
+ 0x9061, 0x04,
+ 0x9062, 0xf0,
+ 0x9063, 0x22,
+ 0xc914, 0x72,
+ 0xc915, 0x92,
+ 0xc916, 0x80,
+ 0xc917, 0x64,
+ 0x9064, 0x74,
+ 0x9065, 0x01,
+ 0x9066, 0x02,
+ 0x9067, 0x72,
+ 0x9068, 0x95,
+ 0xc918, 0x47,
+ 0xc919, 0xf2,
+ 0xc91a, 0x81,
+ 0xc91b, 0x69,
+ 0x9169, 0x74,
+ 0x916a, 0x02,
+ 0x916b, 0xf0,
+ 0x916c, 0xec,
+ 0x916d, 0xb4,
+ 0x916e, 0x10,
+ 0x916f, 0x0a,
+ 0x9170, 0x90,
+ 0x9171, 0x80,
+ 0x9172, 0x16,
+ 0x9173, 0xe0,
+ 0x9174, 0x70,
+ 0x9175, 0x04,
+ 0x9176, 0x90,
+ 0x9177, 0xd3,
+ 0x9178, 0xc4,
+ 0x9179, 0xf0,
+ 0x917a, 0x22,
+ 0xc91c, 0x0a,
+ 0xc91d, 0xbe,
+ 0xc91e, 0x80,
+ 0xc91f, 0x73,
+ 0x9073, 0xfc,
+ 0x9074, 0xa3,
+ 0x9075, 0xe0,
+ 0x9076, 0xf5,
+ 0x9077, 0x82,
+ 0x9078, 0x8c,
+ 0x9079, 0x83,
+ 0x907a, 0xa3,
+ 0x907b, 0xa3,
+ 0x907c, 0xe0,
+ 0x907d, 0xfc,
+ 0x907e, 0xa3,
+ 0x907f, 0xe0,
+ 0x9080, 0xc3,
+ 0x9081, 0x9f,
+ 0x9082, 0xff,
+ 0x9083, 0xec,
+ 0x9084, 0x9e,
+ 0x9085, 0xfe,
+ 0x9086, 0x02,
+ 0x9087, 0x0a,
+ 0x9088, 0xea,
+ 0xc920, 0x47,
+ 0xc921, 0x38,
+ 0xc922, 0x80,
+ 0xc923, 0x89,
+ 0x9089, 0xec,
+ 0x908a, 0xd3,
+ 0x908b, 0x94,
+ 0x908c, 0x20,
+ 0x908d, 0x40,
+ 0x908e, 0x01,
+ 0x908f, 0x1c,
+ 0x9090, 0x90,
+ 0x9091, 0xd3,
+ 0x9092, 0xd4,
+ 0x9093, 0xec,
+ 0x9094, 0xf0,
+ 0x9095, 0x02,
+ 0x9096, 0x47,
+ 0x9097, 0x3d,
+ 0xc924, 0x45,
+ 0xc925, 0xca,
+ 0xc926, 0x80,
+ 0xc927, 0x98,
+ 0x9098, 0x12,
+ 0x9099, 0x77,
+ 0x909a, 0xd6,
+ 0x909b, 0x02,
+ 0x909c, 0x45,
+ 0x909d, 0xcd,
+ 0xc928, 0x20,
+ 0xc929, 0xd5,
+ 0xc92a, 0x80,
+ 0xc92b, 0x9e,
+ 0x909e, 0x90,
+ 0x909f, 0x82,
+ 0x90a0, 0x18,
+ 0x90a1, 0xe0,
+ 0x90a2, 0xb4,
+ 0x90a3, 0x03,
+ 0x90a4, 0x0e,
+ 0x90a5, 0x90,
+ 0x90a6, 0x83,
+ 0x90a7, 0xbf,
+ 0x90a8, 0xe0,
+ 0x90a9, 0x60,
+ 0x90aa, 0x08,
+ 0x90ab, 0x90,
+ 0x90ac, 0x81,
+ 0x90ad, 0xfc,
+ 0x90ae, 0xe0,
+ 0x90af, 0xff,
+ 0x90b0, 0xc3,
+ 0x90b1, 0x13,
+ 0x90b2, 0xf0,
+ 0x90b3, 0x90,
+ 0x90b4, 0x81,
+ 0x90b5, 0xfc,
+ 0x90b6, 0xe0,
+ 0x90b7, 0xff,
+ 0x90b8, 0x02,
+ 0x90b9, 0x20,
+ 0x90ba, 0xda,
+ 0xc92c, 0x70,
+ 0xc92d, 0xbc,
+ 0xc92e, 0x80,
+ 0xc92f, 0xbb,
+ 0x90bb, 0x90,
+ 0x90bc, 0x82,
+ 0x90bd, 0x18,
+ 0x90be, 0xe0,
+ 0x90bf, 0xb4,
+ 0x90c0, 0x03,
+ 0x90c1, 0x06,
+ 0x90c2, 0x90,
+ 0x90c3, 0xc1,
+ 0x90c4, 0x06,
+ 0x90c5, 0x74,
+ 0x90c6, 0x05,
+ 0x90c7, 0xf0,
+ 0x90c8, 0x90,
+ 0x90c9, 0xd3,
+ 0x90ca, 0xa0,
+ 0x90cb, 0x02,
+ 0x90cc, 0x70,
+ 0x90cd, 0xbf,
+ 0xc930, 0x72,
+ 0xc931, 0x21,
+ 0xc932, 0x81,
+ 0xc933, 0x3b,
+ 0x913b, 0x7d,
+ 0x913c, 0x02,
+ 0x913d, 0x7f,
+ 0x913e, 0x7b,
+ 0x913f, 0x02,
+ 0x9140, 0x72,
+ 0x9141, 0x25,
+ 0xc934, 0x28,
+ 0xc935, 0xae,
+ 0xc936, 0x80,
+ 0xc937, 0xd2,
+ 0x90d2, 0xf0,
+ 0x90d3, 0x90,
+ 0x90d4, 0xd2,
+ 0x90d5, 0x0a,
+ 0x90d6, 0x02,
+ 0x90d7, 0x28,
+ 0x90d8, 0xb4,
+ 0xc938, 0x28,
+ 0xc939, 0xb1,
+ 0xc93a, 0x80,
+ 0xc93b, 0xd9,
+ 0x90d9, 0x90,
+ 0x90da, 0x83,
+ 0x90db, 0xba,
+ 0x90dc, 0xe0,
+ 0x90dd, 0xff,
+ 0x90de, 0x90,
+ 0x90df, 0xd2,
+ 0x90e0, 0x08,
+ 0x90e1, 0xe0,
+ 0x90e2, 0xe4,
+ 0x90e3, 0xef,
+ 0x90e4, 0xf0,
+ 0x90e5, 0xa3,
+ 0x90e6, 0xe0,
+ 0x90e7, 0x74,
+ 0x90e8, 0xff,
+ 0x90e9, 0xf0,
+ 0x90ea, 0x90,
+ 0x90eb, 0xd2,
+ 0x90ec, 0x0a,
+ 0x90ed, 0x02,
+ 0x90ee, 0x28,
+ 0x90ef, 0xb4,
+ 0xc93c, 0x29,
+ 0xc93d, 0x79,
+ 0xc93e, 0x80,
+ 0xc93f, 0xf0,
+ 0x90f0, 0xf0,
+ 0x90f1, 0x90,
+ 0x90f2, 0xd2,
+ 0x90f3, 0x0e,
+ 0x90f4, 0x02,
+ 0x90f5, 0x29,
+ 0x90f6, 0x7f,
+ 0xc940, 0x29,
+ 0xc941, 0x7c,
+ 0xc942, 0x80,
+ 0xc943, 0xf7,
+ 0x90f7, 0x90,
+ 0x90f8, 0x83,
+ 0x90f9, 0xba,
+ 0x90fa, 0xe0,
+ 0x90fb, 0xff,
+ 0x90fc, 0x90,
+ 0x90fd, 0xd2,
+ 0x90fe, 0x0c,
+ 0x90ff, 0xe0,
+ 0x9100, 0xe4,
+ 0x9101, 0xef,
+ 0x9102, 0xf0,
+ 0x9103, 0xa3,
+ 0x9104, 0xe0,
+ 0x9105, 0x74,
+ 0x9106, 0xff,
+ 0x9107, 0xf0,
+ 0x9108, 0x90,
+ 0x9109, 0xd2,
+ 0x910a, 0x0e,
+ 0x910b, 0x02,
+ 0x910c, 0x29,
+ 0x910d, 0x7f,
+ 0xc944, 0x2a,
+ 0xc945, 0x42,
+ 0xc946, 0x81,
+ 0xc947, 0x0e,
+ 0x910e, 0xf0,
+ 0x910f, 0x90,
+ 0x9110, 0xd2,
+ 0x9111, 0x12,
+ 0x9112, 0x02,
+ 0x9113, 0x2a,
+ 0x9114, 0x48,
+ 0xc948, 0x2a,
+ 0xc949, 0x45,
+ 0xc94a, 0x81,
+ 0xc94b, 0x15,
+ 0x9115, 0x90,
+ 0x9116, 0x83,
+ 0x9117, 0xba,
+ 0x9118, 0xe0,
+ 0x9119, 0xff,
+ 0x911a, 0x90,
+ 0x911b, 0xd2,
+ 0x911c, 0x10,
+ 0x911d, 0xe0,
+ 0x911e, 0xe4,
+ 0x911f, 0xef,
+ 0x9120, 0xf0,
+ 0x9121, 0xa3,
+ 0x9122, 0xe0,
+ 0x9123, 0x74,
+ 0x9124, 0xff,
+ 0x9125, 0xf0,
+ 0x9126, 0x90,
+ 0x9127, 0xd2,
+ 0x9128, 0x12,
+ 0x9129, 0x02,
+ 0x912a, 0x2a,
+ 0x912b, 0x48,
+ 0xc900, 0x01,
+ 0x0000, 0x00,
+};
+
+static const u16 vs6624_p2[] = {
+ 0x806f, 0x01,
+ 0x058c, 0x01,
+ 0x0000, 0x00,
+};
+
+static const u16 vs6624_run_setup[] = {
+ 0x1d18, 0x00, /* Enableconstrainedwhitebalance */
+ VS6624_PEAK_MIN_OUT_G_MSB, 0x3c, /* Damper PeakGain Output MSB */
+ VS6624_PEAK_MIN_OUT_G_LSB, 0x66, /* Damper PeakGain Output LSB */
+ VS6624_CM_LOW_THR_MSB, 0x65, /* Damper Low MSB */
+ VS6624_CM_LOW_THR_LSB, 0xd1, /* Damper Low LSB */
+ VS6624_CM_HIGH_THR_MSB, 0x66, /* Damper High MSB */
+ VS6624_CM_HIGH_THR_LSB, 0x62, /* Damper High LSB */
+ VS6624_CM_MIN_OUT_MSB, 0x00, /* Damper Min output MSB */
+ VS6624_CM_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */
+ VS6624_NORA_DISABLE, 0x00, /* Nora fDisable */
+ VS6624_NORA_USAGE, 0x04, /* Nora usage */
+ VS6624_NORA_LOW_THR_MSB, 0x63, /* Damper Low MSB Changed 0x63 to 0x65 */
+ VS6624_NORA_LOW_THR_LSB, 0xd1, /* Damper Low LSB */
+ VS6624_NORA_HIGH_THR_MSB, 0x68, /* Damper High MSB */
+ VS6624_NORA_HIGH_THR_LSB, 0xdd, /* Damper High LSB */
+ VS6624_NORA_MIN_OUT_MSB, 0x3a, /* Damper Min output MSB */
+ VS6624_NORA_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */
+ VS6624_F2B_DISABLE, 0x00, /* Disable */
+ 0x1d8a, 0x30, /* MAXWeightHigh */
+ 0x1d91, 0x62, /* fpDamperLowThresholdHigh MSB */
+ 0x1d92, 0x4a, /* fpDamperLowThresholdHigh LSB */
+ 0x1d95, 0x65, /* fpDamperHighThresholdHigh MSB */
+ 0x1d96, 0x0e, /* fpDamperHighThresholdHigh LSB */
+ 0x1da1, 0x3a, /* fpMinimumDamperOutputLow MSB */
+ 0x1da2, 0xb8, /* fpMinimumDamperOutputLow LSB */
+ 0x1e08, 0x06, /* MAXWeightLow */
+ 0x1e0a, 0x0a, /* MAXWeightHigh */
+ 0x1601, 0x3a, /* Red A MSB */
+ 0x1602, 0x14, /* Red A LSB */
+ 0x1605, 0x3b, /* Blue A MSB */
+ 0x1606, 0x85, /* BLue A LSB */
+ 0x1609, 0x3b, /* RED B MSB */
+ 0x160a, 0x85, /* RED B LSB */
+ 0x160d, 0x3a, /* Blue B MSB */
+ 0x160e, 0x14, /* Blue B LSB */
+ 0x1611, 0x30, /* Max Distance from Locus MSB */
+ 0x1612, 0x8f, /* Max Distance from Locus MSB */
+ 0x1614, 0x01, /* Enable constrainer */
+ 0x0000, 0x00,
+};
+
+static const u16 vs6624_default[] = {
+ VS6624_CONTRAST0, 0x84,
+ VS6624_SATURATION0, 0x75,
+ VS6624_GAMMA0, 0x11,
+ VS6624_CONTRAST1, 0x84,
+ VS6624_SATURATION1, 0x75,
+ VS6624_GAMMA1, 0x11,
+ VS6624_MAN_RG, 0x80,
+ VS6624_MAN_GG, 0x80,
+ VS6624_MAN_BG, 0x80,
+ VS6624_WB_MODE, 0x1,
+ VS6624_EXPO_COMPENSATION, 0xfe,
+ VS6624_EXPO_METER, 0x0,
+ VS6624_LIGHT_FREQ, 0x64,
+ VS6624_PEAK_GAIN, 0xe,
+ VS6624_PEAK_LOW_THR, 0x28,
+ VS6624_HMIRROR0, 0x0,
+ VS6624_VFLIP0, 0x0,
+ VS6624_ZOOM_HSTEP0_MSB, 0x0,
+ VS6624_ZOOM_HSTEP0_LSB, 0x1,
+ VS6624_ZOOM_VSTEP0_MSB, 0x0,
+ VS6624_ZOOM_VSTEP0_LSB, 0x1,
+ VS6624_PAN_HSTEP0_MSB, 0x0,
+ VS6624_PAN_HSTEP0_LSB, 0xf,
+ VS6624_PAN_VSTEP0_MSB, 0x0,
+ VS6624_PAN_VSTEP0_LSB, 0xf,
+ VS6624_SENSOR_MODE, 0x1,
+ VS6624_SYNC_CODE_SETUP, 0x21,
+ VS6624_DISABLE_FR_DAMPER, 0x0,
+ VS6624_FR_DEN, 0x1,
+ VS6624_FR_NUM_LSB, 0xf,
+ VS6624_INIT_PIPE_SETUP, 0x0,
+ VS6624_IMG_FMT0, 0x0,
+ VS6624_YUV_SETUP, 0x1,
+ VS6624_IMAGE_SIZE0, 0x2,
+ 0x0000, 0x00,
+};
+
+static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct vs6624, sd);
+}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
+}
+
+static int vs6624_read(struct v4l2_subdev *sd, u16 index)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 buf[2];
+
+ buf[0] = index >> 8;
+ buf[1] = index;
+ i2c_master_send(client, buf, 2);
+ i2c_master_recv(client, buf, 1);
+
+ return buf[0];
+}
+
+static int vs6624_write(struct v4l2_subdev *sd, u16 index,
+ u8 value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 buf[3];
+
+ buf[0] = index >> 8;
+ buf[1] = index;
+ buf[2] = value;
+
+ return i2c_master_send(client, buf, 3);
+}
+
+static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
+{
+ u16 reg;
+ u8 data;
+
+ while (*regs != 0x00) {
+ reg = *regs++;
+ data = *regs++;
+
+ vs6624_write(sd, reg, data);
+ }
+ return 0;
+}
+
+static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_CONTRAST:
+ vs6624_write(sd, VS6624_CONTRAST0, ctrl->val);
+ break;
+ case V4L2_CID_SATURATION:
+ vs6624_write(sd, VS6624_SATURATION0, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ vs6624_write(sd, VS6624_HMIRROR0, ctrl->val);
+ break;
+ case V4L2_CID_VFLIP:
+ vs6624_write(sd, VS6624_VFLIP0, ctrl->val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vs6624_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(vs6624_formats))
+ return -EINVAL;
+
+ *code = vs6624_formats[index].mbus_code;
+ return 0;
+}
+
+static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
+ if (vs6624_formats[index].mbus_code == fmt->code)
+ break;
+ if (index >= ARRAY_SIZE(vs6624_formats)) {
+ /* default to first format */
+ index = 0;
+ fmt->code = vs6624_formats[0].mbus_code;
+ }
+
+ /* sensor mode is VGA */
+ if (fmt->width > VGA_WIDTH)
+ fmt->width = VGA_WIDTH;
+ if (fmt->height > VGA_HEIGHT)
+ fmt->height = VGA_HEIGHT;
+ fmt->width = fmt->width & (~3);
+ fmt->height = fmt->height & (~3);
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = vs6624_formats[index].colorspace;
+ return 0;
+}
+
+static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct vs6624 *sensor = to_vs6624(sd);
+ int ret;
+
+ ret = vs6624_try_mbus_fmt(sd, fmt);
+ if (ret)
+ return ret;
+
+ /* set image format */
+ switch (fmt->code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
+ vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
+ break;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
+ vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
+ break;
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
+ vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set image size */
+ if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
+ else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
+ else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
+ else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
+ else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
+ else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
+ else {
+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
+ vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
+ vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
+ vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
+ vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
+ vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
+ }
+
+ sensor->fmt = *fmt;
+
+ return 0;
+}
+
+static int vs6624_g_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct vs6624 *sensor = to_vs6624(sd);
+
+ *fmt = sensor->fmt;
+ return 0;
+}
+
+static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct vs6624 *sensor = to_vs6624(sd);
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(cp, 0, sizeof(*cp));
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = sensor->frame_rate.denominator;
+ cp->timeperframe.denominator = sensor->frame_rate.numerator;
+ return 0;
+}
+
+static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct vs6624 *sensor = to_vs6624(sd);
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ struct v4l2_fract *tpf = &cp->timeperframe;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (cp->extendedmode != 0)
+ return -EINVAL;
+
+ if (tpf->numerator == 0 || tpf->denominator == 0
+ || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
+ /* reset to max frame rate */
+ tpf->numerator = 1;
+ tpf->denominator = MAX_FRAME_RATE;
+ }
+ sensor->frame_rate.numerator = tpf->denominator;
+ sensor->frame_rate.denominator = tpf->numerator;
+ vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
+ vs6624_write(sd, VS6624_FR_NUM_MSB,
+ sensor->frame_rate.numerator >> 8);
+ vs6624_write(sd, VS6624_FR_NUM_LSB,
+ sensor->frame_rate.numerator & 0xFF);
+ vs6624_write(sd, VS6624_FR_DEN,
+ sensor->frame_rate.denominator & 0xFF);
+ return 0;
+}
+
+static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ if (enable)
+ vs6624_write(sd, VS6624_USER_CMD, 0x2);
+ else
+ vs6624_write(sd, VS6624_USER_CMD, 0x4);
+ udelay(100);
+ return 0;
+}
+
+static int vs6624_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ int rev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ rev = (vs6624_read(sd, VS6624_FW_VSN_MAJOR) << 8)
+ | vs6624_read(sd, VS6624_FW_VSN_MINOR);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VS6624, rev);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = vs6624_read(sd, reg->reg & 0xffff);
+ reg->size = 1;
+ return 0;
+}
+
+static int vs6624_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
+ return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
+ .s_ctrl = vs6624_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops vs6624_core_ops = {
+ .g_chip_ident = vs6624_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = vs6624_g_register,
+ .s_register = vs6624_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops vs6624_video_ops = {
+ .enum_mbus_fmt = vs6624_enum_mbus_fmt,
+ .try_mbus_fmt = vs6624_try_mbus_fmt,
+ .s_mbus_fmt = vs6624_s_mbus_fmt,
+ .g_mbus_fmt = vs6624_g_mbus_fmt,
+ .s_parm = vs6624_s_parm,
+ .g_parm = vs6624_g_parm,
+ .s_stream = vs6624_s_stream,
+};
+
+static const struct v4l2_subdev_ops vs6624_ops = {
+ .core = &vs6624_core_ops,
+ .video = &vs6624_video_ops,
+};
+
+static int __devinit vs6624_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct vs6624 *sensor;
+ struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *hdl;
+ const unsigned *ce;
+ int ret;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -EIO;
+
+ ce = client->dev.platform_data;
+ if (ce == NULL)
+ return -EINVAL;
+
+ ret = gpio_request(*ce, "VS6624 Chip Enable");
+ if (ret) {
+ v4l_err(client, "failed to request GPIO %d\n", *ce);
+ return ret;
+ }
+ gpio_direction_output(*ce, 1);
+ /* wait 100ms before any further i2c writes are performed */
+ mdelay(100);
+
+ sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+ if (sensor == NULL) {
+ gpio_free(*ce);
+ return -ENOMEM;
+ }
+
+ sd = &sensor->sd;
+ v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
+
+ vs6624_writeregs(sd, vs6624_p1);
+ vs6624_write(sd, VS6624_MICRO_EN, 0x2);
+ vs6624_write(sd, VS6624_DIO_EN, 0x1);
+ mdelay(10);
+ vs6624_writeregs(sd, vs6624_p2);
+
+ vs6624_writeregs(sd, vs6624_default);
+ vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
+ vs6624_writeregs(sd, vs6624_run_setup);
+
+ /* set frame rate */
+ sensor->frame_rate.numerator = MAX_FRAME_RATE;
+ sensor->frame_rate.denominator = 1;
+ vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
+ vs6624_write(sd, VS6624_FR_NUM_MSB,
+ sensor->frame_rate.numerator >> 8);
+ vs6624_write(sd, VS6624_FR_NUM_LSB,
+ sensor->frame_rate.numerator & 0xFF);
+ vs6624_write(sd, VS6624_FR_DEN,
+ sensor->frame_rate.denominator & 0xFF);
+
+ sensor->fmt = vs6624_default_fmt;
+ sensor->ce_pin = *ce;
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ hdl = &sensor->hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
+ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
+ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ /* hook the control handler into the driver */
+ sd->ctrl_handler = hdl;
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(sensor);
+ gpio_free(*ce);
+ return err;
+ }
+
+ /* initialize the hardware to the default control values */
+ ret = v4l2_ctrl_handler_setup(hdl);
+ if (ret) {
+ v4l2_ctrl_handler_free(hdl);
+ kfree(sensor);
+ gpio_free(*ce);
+ }
+ return ret;
+}
+
+static int __devexit vs6624_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct vs6624 *sensor = to_vs6624(sd);
+
+ v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+ gpio_free(sensor->ce_pin);
+ kfree(sensor);
+ return 0;
+}
+
+static const struct i2c_device_id vs6624_id[] = {
+ {"vs6624", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, vs6624_id);
+
+static struct i2c_driver vs6624_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "vs6624",
+ },
+ .probe = vs6624_probe,
+ .remove = __devexit_p(vs6624_remove),
+ .id_table = vs6624_id,
+};
+
+static __init int vs6624_init(void)
+{
+ return i2c_add_driver(&vs6624_driver);
+}
+
+static __exit void vs6624_exit(void)
+{
+ i2c_del_driver(&vs6624_driver);
+}
+
+module_init(vs6624_init);
+module_exit(vs6624_exit);
+
+MODULE_DESCRIPTION("VS6624 sensor driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/vs6624_regs.h b/drivers/media/video/vs6624_regs.h
new file mode 100644
index 000000000000..6ba2ee25827e
--- /dev/null
+++ b/drivers/media/video/vs6624_regs.h
@@ -0,0 +1,337 @@
+/*
+ * vs6624 - ST VS6624 CMOS image sensor registers
+ *
+ * Copyright (c) 2011 Analog Devices 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.
+ *
+ * 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 _VS6624_REGS_H_
+#define _VS6624_REGS_H_
+
+/* low level control registers */
+#define VS6624_MICRO_EN 0xC003 /* power enable for all MCU clock */
+#define VS6624_DIO_EN 0xC044 /* enable digital I/O */
+/* device parameters */
+#define VS6624_DEV_ID_MSB 0x0001 /* device id MSB */
+#define VS6624_DEV_ID_LSB 0x0002 /* device id LSB */
+#define VS6624_FW_VSN_MAJOR 0x0004 /* firmware version major */
+#define VS6624_FW_VSN_MINOR 0x0006 /* firmware version minor */
+#define VS6624_PATCH_VSN_MAJOR 0x0008 /* patch version major */
+#define VS6624_PATCH_VSN_MINOR 0x000A /* patch version minor */
+/* host interface manager control */
+#define VS6624_USER_CMD 0x0180 /* user level control of operating states */
+/* host interface manager status */
+#define VS6624_STATE 0x0202 /* current state of the mode manager */
+/* run mode control */
+#define VS6624_METER_ON 0x0280 /* if false AE and AWB are disabled */
+/* mode setup */
+#define VS6624_ACTIVE_PIPE_SETUP 0x0302 /* select the active bank for non view live mode */
+#define VS6624_SENSOR_MODE 0x0308 /* select the different sensor mode */
+/* pipe setup bank0 */
+#define VS6624_IMAGE_SIZE0 0x0380 /* required output dimension */
+#define VS6624_MAN_HSIZE0_MSB 0x0383 /* input required manual H size MSB */
+#define VS6624_MAN_HSIZE0_LSB 0x0384 /* input required manual H size LSB */
+#define VS6624_MAN_VSIZE0_MSB 0x0387 /* input required manual V size MSB */
+#define VS6624_MAN_VSIZE0_LSB 0x0388 /* input required manual V size LSB */
+#define VS6624_ZOOM_HSTEP0_MSB 0x038B /* set the zoom H step MSB */
+#define VS6624_ZOOM_HSTEP0_LSB 0x038C /* set the zoom H step LSB */
+#define VS6624_ZOOM_VSTEP0_MSB 0x038F /* set the zoom V step MSB */
+#define VS6624_ZOOM_VSTEP0_LSB 0x0390 /* set the zoom V step LSB */
+#define VS6624_ZOOM_CTRL0 0x0392 /* control zoon in, out and stop */
+#define VS6624_PAN_HSTEP0_MSB 0x0395 /* set the pan H step MSB */
+#define VS6624_PAN_HSTEP0_LSB 0x0396 /* set the pan H step LSB */
+#define VS6624_PAN_VSTEP0_MSB 0x0399 /* set the pan V step MSB */
+#define VS6624_PAN_VSTEP0_LSB 0x039A /* set the pan V step LSB */
+#define VS6624_PAN_CTRL0 0x039C /* control pan operation */
+#define VS6624_CROP_CTRL0 0x039E /* select cropping mode */
+#define VS6624_CROP_HSTART0_MSB 0x03A1 /* set the cropping H start address MSB */
+#define VS6624_CROP_HSTART0_LSB 0x03A2 /* set the cropping H start address LSB */
+#define VS6624_CROP_HSIZE0_MSB 0x03A5 /* set the cropping H size MSB */
+#define VS6624_CROP_HSIZE0_LSB 0x03A6 /* set the cropping H size LSB */
+#define VS6624_CROP_VSTART0_MSB 0x03A9 /* set the cropping V start address MSB */
+#define VS6624_CROP_VSTART0_LSB 0x03AA /* set the cropping V start address LSB */
+#define VS6624_CROP_VSIZE0_MSB 0x03AD /* set the cropping V size MSB */
+#define VS6624_CROP_VSIZE0_LSB 0x03AE /* set the cropping V size LSB */
+#define VS6624_IMG_FMT0 0x03B0 /* select required output image format */
+#define VS6624_BAYER_OUT_ALIGN0 0x03B2 /* set bayer output alignment */
+#define VS6624_CONTRAST0 0x03B4 /* contrast control for output */
+#define VS6624_SATURATION0 0x03B6 /* saturation control for output */
+#define VS6624_GAMMA0 0x03B8 /* gamma settings */
+#define VS6624_HMIRROR0 0x03BA /* horizontal image orientation flip */
+#define VS6624_VFLIP0 0x03BC /* vertical image orientation flip */
+#define VS6624_CHANNEL_ID0 0x03BE /* logical DMA channel number */
+/* pipe setup bank1 */
+#define VS6624_IMAGE_SIZE1 0x0400 /* required output dimension */
+#define VS6624_MAN_HSIZE1_MSB 0x0403 /* input required manual H size MSB */
+#define VS6624_MAN_HSIZE1_LSB 0x0404 /* input required manual H size LSB */
+#define VS6624_MAN_VSIZE1_MSB 0x0407 /* input required manual V size MSB */
+#define VS6624_MAN_VSIZE1_LSB 0x0408 /* input required manual V size LSB */
+#define VS6624_ZOOM_HSTEP1_MSB 0x040B /* set the zoom H step MSB */
+#define VS6624_ZOOM_HSTEP1_LSB 0x040C /* set the zoom H step LSB */
+#define VS6624_ZOOM_VSTEP1_MSB 0x040F /* set the zoom V step MSB */
+#define VS6624_ZOOM_VSTEP1_LSB 0x0410 /* set the zoom V step LSB */
+#define VS6624_ZOOM_CTRL1 0x0412 /* control zoon in, out and stop */
+#define VS6624_PAN_HSTEP1_MSB 0x0415 /* set the pan H step MSB */
+#define VS6624_PAN_HSTEP1_LSB 0x0416 /* set the pan H step LSB */
+#define VS6624_PAN_VSTEP1_MSB 0x0419 /* set the pan V step MSB */
+#define VS6624_PAN_VSTEP1_LSB 0x041A /* set the pan V step LSB */
+#define VS6624_PAN_CTRL1 0x041C /* control pan operation */
+#define VS6624_CROP_CTRL1 0x041E /* select cropping mode */
+#define VS6624_CROP_HSTART1_MSB 0x0421 /* set the cropping H start address MSB */
+#define VS6624_CROP_HSTART1_LSB 0x0422 /* set the cropping H start address LSB */
+#define VS6624_CROP_HSIZE1_MSB 0x0425 /* set the cropping H size MSB */
+#define VS6624_CROP_HSIZE1_LSB 0x0426 /* set the cropping H size LSB */
+#define VS6624_CROP_VSTART1_MSB 0x0429 /* set the cropping V start address MSB */
+#define VS6624_CROP_VSTART1_LSB 0x042A /* set the cropping V start address LSB */
+#define VS6624_CROP_VSIZE1_MSB 0x042D /* set the cropping V size MSB */
+#define VS6624_CROP_VSIZE1_LSB 0x042E /* set the cropping V size LSB */
+#define VS6624_IMG_FMT1 0x0430 /* select required output image format */
+#define VS6624_BAYER_OUT_ALIGN1 0x0432 /* set bayer output alignment */
+#define VS6624_CONTRAST1 0x0434 /* contrast control for output */
+#define VS6624_SATURATION1 0x0436 /* saturation control for output */
+#define VS6624_GAMMA1 0x0438 /* gamma settings */
+#define VS6624_HMIRROR1 0x043A /* horizontal image orientation flip */
+#define VS6624_VFLIP1 0x043C /* vertical image orientation flip */
+#define VS6624_CHANNEL_ID1 0x043E /* logical DMA channel number */
+/* view live control */
+#define VS6624_VIEW_LIVE_EN 0x0480 /* enable view live mode */
+#define VS6624_INIT_PIPE_SETUP 0x0482 /* select initial pipe setup bank */
+/* view live status */
+#define VS6624_CUR_PIPE_SETUP 0x0500 /* indicates most recently applied setup bank */
+/* power management */
+#define VS6624_TIME_TO_POWER_DOWN 0x0580 /* automatically transition time to stop mode */
+/* video timing parameter host inputs */
+#define VS6624_EXT_CLK_FREQ_NUM_MSB 0x0605 /* external clock frequency numerator MSB */
+#define VS6624_EXT_CLK_FREQ_NUM_LSB 0x0606 /* external clock frequency numerator LSB */
+#define VS6624_EXT_CLK_FREQ_DEN 0x0608 /* external clock frequency denominator */
+/* video timing control */
+#define VS6624_SYS_CLK_MODE 0x0880 /* decides system clock frequency */
+/* frame dimension parameter host inputs */
+#define VS6624_LIGHT_FREQ 0x0C80 /* AC frequency used for flicker free time */
+#define VS6624_FLICKER_COMPAT 0x0C82 /* flicker compatible frame length */
+/* static frame rate control */
+#define VS6624_FR_NUM_MSB 0x0D81 /* desired frame rate numerator MSB */
+#define VS6624_FR_NUM_LSB 0x0D82 /* desired frame rate numerator LSB */
+#define VS6624_FR_DEN 0x0D84 /* desired frame rate denominator */
+/* automatic frame rate control */
+#define VS6624_DISABLE_FR_DAMPER 0x0E80 /* defines frame rate mode */
+#define VS6624_MIN_DAMPER_OUT_MSB 0x0E8C /* minimum frame rate MSB */
+#define VS6624_MIN_DAMPER_OUT_LSB 0x0E8A /* minimum frame rate LSB */
+/* exposure controls */
+#define VS6624_EXPO_MODE 0x1180 /* exposure mode */
+#define VS6624_EXPO_METER 0x1182 /* weights to be associated with the zones */
+#define VS6624_EXPO_TIME_NUM 0x1184 /* exposure time numerator */
+#define VS6624_EXPO_TIME_DEN 0x1186 /* exposure time denominator */
+#define VS6624_EXPO_TIME_MSB 0x1189 /* exposure time for the Manual Mode MSB */
+#define VS6624_EXPO_TIME_LSB 0x118A /* exposure time for the Manual Mode LSB */
+#define VS6624_EXPO_COMPENSATION 0x1190 /* exposure compensation */
+#define VS6624_DIRECT_COARSE_MSB 0x1195 /* coarse integration lines for Direct Mode MSB */
+#define VS6624_DIRECT_COARSE_LSB 0x1196 /* coarse integration lines for Direct Mode LSB */
+#define VS6624_DIRECT_FINE_MSB 0x1199 /* fine integration pixels for Direct Mode MSB */
+#define VS6624_DIRECT_FINE_LSB 0x119A /* fine integration pixels for Direct Mode LSB */
+#define VS6624_DIRECT_ANAL_GAIN_MSB 0x119D /* analog gain for Direct Mode MSB */
+#define VS6624_DIRECT_ANAL_GAIN_LSB 0x119E /* analog gain for Direct Mode LSB */
+#define VS6624_DIRECT_DIGI_GAIN_MSB 0x11A1 /* digital gain for Direct Mode MSB */
+#define VS6624_DIRECT_DIGI_GAIN_LSB 0x11A2 /* digital gain for Direct Mode LSB */
+#define VS6624_FLASH_COARSE_MSB 0x11A5 /* coarse integration lines for Flash Gun Mode MSB */
+#define VS6624_FLASH_COARSE_LSB 0x11A6 /* coarse integration lines for Flash Gun Mode LSB */
+#define VS6624_FLASH_FINE_MSB 0x11A9 /* fine integration pixels for Flash Gun Mode MSB */
+#define VS6624_FLASH_FINE_LSB 0x11AA /* fine integration pixels for Flash Gun Mode LSB */
+#define VS6624_FLASH_ANAL_GAIN_MSB 0x11AD /* analog gain for Flash Gun Mode MSB */
+#define VS6624_FLASH_ANAL_GAIN_LSB 0x11AE /* analog gain for Flash Gun Mode LSB */
+#define VS6624_FLASH_DIGI_GAIN_MSB 0x11B1 /* digital gain for Flash Gun Mode MSB */
+#define VS6624_FLASH_DIGI_GAIN_LSB 0x11B2 /* digital gain for Flash Gun Mode LSB */
+#define VS6624_FREEZE_AE 0x11B4 /* freeze auto exposure */
+#define VS6624_MAX_INT_TIME_MSB 0x11B7 /* user maximum integration time MSB */
+#define VS6624_MAX_INT_TIME_LSB 0x11B8 /* user maximum integration time LSB */
+#define VS6624_FLASH_AG_THR_MSB 0x11BB /* recommend flash gun analog gain threshold MSB */
+#define VS6624_FLASH_AG_THR_LSB 0x11BC /* recommend flash gun analog gain threshold LSB */
+#define VS6624_ANTI_FLICKER_MODE 0x11C0 /* anti flicker mode */
+/* white balance control */
+#define VS6624_WB_MODE 0x1480 /* set white balance mode */
+#define VS6624_MAN_RG 0x1482 /* user setting for red channel gain */
+#define VS6624_MAN_GG 0x1484 /* user setting for green channel gain */
+#define VS6624_MAN_BG 0x1486 /* user setting for blue channel gain */
+#define VS6624_FLASH_RG_MSB 0x148B /* red gain for Flash Gun MSB */
+#define VS6624_FLASH_RG_LSB 0x148C /* red gain for Flash Gun LSB */
+#define VS6624_FLASH_GG_MSB 0x148F /* green gain for Flash Gun MSB */
+#define VS6624_FLASH_GG_LSB 0x1490 /* green gain for Flash Gun LSB */
+#define VS6624_FLASH_BG_MSB 0x1493 /* blue gain for Flash Gun MSB */
+#define VS6624_FLASH_BG_LSB 0x1494 /* blue gain for Flash Gun LSB */
+/* sensor setup */
+#define VS6624_BC_OFFSET 0x1990 /* Black Correction Offset */
+/* image stability */
+#define VS6624_STABLE_WB 0x1900 /* white balance stable */
+#define VS6624_STABLE_EXPO 0x1902 /* exposure stable */
+#define VS6624_STABLE 0x1906 /* system stable */
+/* flash control */
+#define VS6624_FLASH_MODE 0x1A80 /* flash mode */
+#define VS6624_FLASH_OFF_LINE_MSB 0x1A83 /* off line at flash pulse mode MSB */
+#define VS6624_FLASH_OFF_LINE_LSB 0x1A84 /* off line at flash pulse mode LSB */
+/* flash status */
+#define VS6624_FLASH_RECOM 0x1B00 /* flash gun is recommended */
+#define VS6624_FLASH_GRAB_COMPLETE 0x1B02 /* flash gun image has been grabbed */
+/* scythe filter controls */
+#define VS6624_SCYTHE_FILTER 0x1D80 /* disable scythe defect correction */
+/* jack filter controls */
+#define VS6624_JACK_FILTER 0x1E00 /* disable jack defect correction */
+/* demosaic control */
+#define VS6624_ANTI_ALIAS_FILTER 0x1E80 /* anti alias filter suppress */
+/* color matrix dampers */
+#define VS6624_CM_DISABLE 0x1F00 /* disable color matrix damper */
+#define VS6624_CM_LOW_THR_MSB 0x1F03 /* low threshold for exposure MSB */
+#define VS6624_CM_LOW_THR_LSB 0x1F04 /* low threshold for exposure LSB */
+#define VS6624_CM_HIGH_THR_MSB 0x1F07 /* high threshold for exposure MSB */
+#define VS6624_CM_HIGH_THR_LSB 0x1F08 /* high threshold for exposure LSB */
+#define VS6624_CM_MIN_OUT_MSB 0x1F0B /* minimum possible damper output MSB */
+#define VS6624_CM_MIN_OUT_LSB 0x1F0C /* minimum possible damper output LSB */
+/* peaking control */
+#define VS6624_PEAK_GAIN 0x2000 /* controls peaking gain */
+#define VS6624_PEAK_G_DISABLE 0x2002 /* disable peak gain damping */
+#define VS6624_PEAK_LOW_THR_G_MSB 0x2005 /* low threshold for exposure for gain MSB */
+#define VS6624_PEAK_LOW_THR_G_LSB 0x2006 /* low threshold for exposure for gain LSB */
+#define VS6624_PEAK_HIGH_THR_G_MSB 0x2009 /* high threshold for exposure for gain MSB */
+#define VS6624_PEAK_HIGH_THR_G_LSB 0x200A /* high threshold for exposure for gain LSB */
+#define VS6624_PEAK_MIN_OUT_G_MSB 0x200D /* minimum damper output for gain MSB */
+#define VS6624_PEAK_MIN_OUT_G_LSB 0x200E /* minimum damper output for gain LSB */
+#define VS6624_PEAK_LOW_THR 0x2010 /* adjust degree of coring */
+#define VS6624_PEAK_C_DISABLE 0x2012 /* disable coring damping */
+#define VS6624_PEAK_HIGH_THR 0x2014 /* adjust maximum gain */
+#define VS6624_PEAK_LOW_THR_C_MSB 0x2017 /* low threshold for exposure for coring MSB */
+#define VS6624_PEAK_LOW_THR_C_LSB 0x2018 /* low threshold for exposure for coring LSB */
+#define VS6624_PEAK_HIGH_THR_C_MSB 0x201B /* high threshold for exposure for coring MSB */
+#define VS6624_PEAK_HIGH_THR_C_LSB 0x201C /* high threshold for exposure for coring LSB */
+#define VS6624_PEAK_MIN_OUT_C_MSB 0x201F /* minimum damper output for coring MSB */
+#define VS6624_PEAK_MIN_OUT_C_LSB 0x2020 /* minimum damper output for coring LSB */
+/* pipe 0 RGB to YUV matrix manual control */
+#define VS6624_RYM0_MAN_CTRL 0x2180 /* enable manual RGB to YUV matrix */
+#define VS6624_RYM0_W00_MSB 0x2183 /* row 0 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W00_LSB 0x2184 /* row 0 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W01_MSB 0x2187 /* row 0 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W01_LSB 0x2188 /* row 0 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W02_MSB 0x218C /* row 0 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W02_LSB 0x218D /* row 0 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_W10_MSB 0x2190 /* row 1 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W10_LSB 0x218F /* row 1 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W11_MSB 0x2193 /* row 1 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W11_LSB 0x2194 /* row 1 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W12_MSB 0x2197 /* row 1 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W12_LSB 0x2198 /* row 1 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_W20_MSB 0x219B /* row 2 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W20_LSB 0x219C /* row 2 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W21_MSB 0x21A0 /* row 2 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W21_LSB 0x219F /* row 2 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W22_MSB 0x21A3 /* row 2 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W22_LSB 0x21A4 /* row 2 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_YINY_MSB 0x21A7 /* Y in Y MSB */
+#define VS6624_RYM0_YINY_LSB 0x21A8 /* Y in Y LSB */
+#define VS6624_RYM0_YINCB_MSB 0x21AB /* Y in Cb MSB */
+#define VS6624_RYM0_YINCB_LSB 0x21AC /* Y in Cb LSB */
+#define VS6624_RYM0_YINCR_MSB 0x21B0 /* Y in Cr MSB */
+#define VS6624_RYM0_YINCR_LSB 0x21AF /* Y in Cr LSB */
+/* pipe 1 RGB to YUV matrix manual control */
+#define VS6624_RYM1_MAN_CTRL 0x2200 /* enable manual RGB to YUV matrix */
+#define VS6624_RYM1_W00_MSB 0x2203 /* row 0 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W00_LSB 0x2204 /* row 0 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W01_MSB 0x2207 /* row 0 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W01_LSB 0x2208 /* row 0 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W02_MSB 0x220C /* row 0 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W02_LSB 0x220D /* row 0 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_W10_MSB 0x2210 /* row 1 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W10_LSB 0x220F /* row 1 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W11_MSB 0x2213 /* row 1 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W11_LSB 0x2214 /* row 1 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W12_MSB 0x2217 /* row 1 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W12_LSB 0x2218 /* row 1 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_W20_MSB 0x221B /* row 2 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W20_LSB 0x221C /* row 2 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W21_MSB 0x2220 /* row 2 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W21_LSB 0x221F /* row 2 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W22_MSB 0x2223 /* row 2 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W22_LSB 0x2224 /* row 2 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_YINY_MSB 0x2227 /* Y in Y MSB */
+#define VS6624_RYM1_YINY_LSB 0x2228 /* Y in Y LSB */
+#define VS6624_RYM1_YINCB_MSB 0x222B /* Y in Cb MSB */
+#define VS6624_RYM1_YINCB_LSB 0x222C /* Y in Cb LSB */
+#define VS6624_RYM1_YINCR_MSB 0x2220 /* Y in Cr MSB */
+#define VS6624_RYM1_YINCR_LSB 0x222F /* Y in Cr LSB */
+/* pipe 0 gamma manual control */
+#define VS6624_GAMMA_MAN_CTRL0 0x2280 /* enable manual gamma setup */
+#define VS6624_GAMMA_PEAK_R0 0x2282 /* peaked red channel gamma value */
+#define VS6624_GAMMA_PEAK_G0 0x2284 /* peaked green channel gamma value */
+#define VS6624_GAMMA_PEAK_B0 0x2286 /* peaked blue channel gamma value */
+#define VS6624_GAMMA_UNPEAK_R0 0x2288 /* unpeaked red channel gamma value */
+#define VS6624_GAMMA_UNPEAK_G0 0x228A /* unpeaked green channel gamma value */
+#define VS6624_GAMMA_UNPEAK_B0 0x228C /* unpeaked blue channel gamma value */
+/* pipe 1 gamma manual control */
+#define VS6624_GAMMA_MAN_CTRL1 0x2300 /* enable manual gamma setup */
+#define VS6624_GAMMA_PEAK_R1 0x2302 /* peaked red channel gamma value */
+#define VS6624_GAMMA_PEAK_G1 0x2304 /* peaked green channel gamma value */
+#define VS6624_GAMMA_PEAK_B1 0x2306 /* peaked blue channel gamma value */
+#define VS6624_GAMMA_UNPEAK_R1 0x2308 /* unpeaked red channel gamma value */
+#define VS6624_GAMMA_UNPEAK_G1 0x230A /* unpeaked green channel gamma value */
+#define VS6624_GAMMA_UNPEAK_B1 0x230C /* unpeaked blue channel gamma value */
+/* fade to black */
+#define VS6624_F2B_DISABLE 0x2480 /* disable fade to black */
+#define VS6624_F2B_BLACK_VAL_MSB 0x2483 /* black value MSB */
+#define VS6624_F2B_BLACK_VAL_LSB 0x2484 /* black value LSB */
+#define VS6624_F2B_LOW_THR_MSB 0x2487 /* low threshold for exposure MSB */
+#define VS6624_F2B_LOW_THR_LSB 0x2488 /* low threshold for exposure LSB */
+#define VS6624_F2B_HIGH_THR_MSB 0x248B /* high threshold for exposure MSB */
+#define VS6624_F2B_HIGH_THR_LSB 0x248C /* high threshold for exposure LSB */
+#define VS6624_F2B_MIN_OUT_MSB 0x248F /* minimum damper output MSB */
+#define VS6624_F2B_MIN_OUT_LSB 0x2490 /* minimum damper output LSB */
+/* output formatter control */
+#define VS6624_CODE_CK_EN 0x2580 /* code check enable */
+#define VS6624_BLANK_FMT 0x2582 /* blank format */
+#define VS6624_SYNC_CODE_SETUP 0x2584 /* sync code setup */
+#define VS6624_HSYNC_SETUP 0x2586 /* H sync setup */
+#define VS6624_VSYNC_SETUP 0x2588 /* V sync setup */
+#define VS6624_PCLK_SETUP 0x258A /* PCLK setup */
+#define VS6624_PCLK_EN 0x258C /* PCLK enable */
+#define VS6624_OPF_SP_SETUP 0x258E /* output formatter sp setup */
+#define VS6624_BLANK_DATA_MSB 0x2590 /* blank data MSB */
+#define VS6624_BLANK_DATA_LSB 0x2592 /* blank data LSB */
+#define VS6624_RGB_SETUP 0x2594 /* RGB setup */
+#define VS6624_YUV_SETUP 0x2596 /* YUV setup */
+#define VS6624_VSYNC_RIS_COARSE_H 0x2598 /* V sync rising coarse high */
+#define VS6624_VSYNC_RIS_COARSE_L 0x259A /* V sync rising coarse low */
+#define VS6624_VSYNC_RIS_FINE_H 0x259C /* V sync rising fine high */
+#define VS6624_VSYNC_RIS_FINE_L 0x259E /* V sync rising fine low */
+#define VS6624_VSYNC_FALL_COARSE_H 0x25A0 /* V sync falling coarse high */
+#define VS6624_VSYNC_FALL_COARSE_L 0x25A2 /* V sync falling coarse low */
+#define VS6624_VSYNC_FALL_FINE_H 0x25A4 /* V sync falling fine high */
+#define VS6624_VSYNC_FALL_FINE_L 0x25A6 /* V sync falling fine low */
+#define VS6624_HSYNC_RIS_H 0x25A8 /* H sync rising high */
+#define VS6624_HSYNC_RIS_L 0x25AA /* H sync rising low */
+#define VS6624_HSYNC_FALL_H 0x25AC /* H sync falling high */
+#define VS6624_HSYNC_FALL_L 0x25AE /* H sync falling low */
+#define VS6624_OUT_IF 0x25B0 /* output interface */
+#define VS6624_CCP_EXT_DATA 0x25B2 /* CCP extra data */
+/* NoRA controls */
+#define VS6624_NORA_DISABLE 0x2600 /* NoRA control mode */
+#define VS6624_NORA_USAGE 0x2602 /* usage */
+#define VS6624_NORA_SPLIT_KN 0x2604 /* split kn */
+#define VS6624_NORA_SPLIT_NI 0x2606 /* split ni */
+#define VS6624_NORA_TIGHT_G 0x2608 /* tight green */
+#define VS6624_NORA_DISABLE_NP 0x260A /* disable noro promoting */
+#define VS6624_NORA_LOW_THR_MSB 0x260D /* low threshold for exposure MSB */
+#define VS6624_NORA_LOW_THR_LSB 0x260E /* low threshold for exposure LSB */
+#define VS6624_NORA_HIGH_THR_MSB 0x2611 /* high threshold for exposure MSB */
+#define VS6624_NORA_HIGH_THR_LSB 0x2612 /* high threshold for exposure LSB */
+#define VS6624_NORA_MIN_OUT_MSB 0x2615 /* minimum damper output MSB */
+#define VS6624_NORA_MIN_OUT_LSB 0x2616 /* minimum damper output LSB */
+
+#endif
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 453dbbd1e6e8..7fd7ac567e1a 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -129,9 +129,9 @@ MODULE_LICENSE("GPL");
MODULE_VERSION("0.33.1");
#ifdef MODULE
-static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
+static char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
#else
-static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
+static char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
#endif
module_param_array(pardev, charp, NULL, 0);
MODULE_PARM_DESC(pardev, "pardev: where to search for\n"
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index a22f765e968a..3bb99e93febe 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -291,15 +291,4 @@ static struct i2c_driver wm8739_driver = {
.id_table = wm8739_id,
};
-static __init int init_wm8739(void)
-{
- return i2c_add_driver(&wm8739_driver);
-}
-
-static __exit void exit_wm8739(void)
-{
- i2c_del_driver(&wm8739_driver);
-}
-
-module_init(init_wm8739);
-module_exit(exit_wm8739);
+module_i2c_driver(wm8739_driver);
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 9cedb1e69b58..bee77ea9f49e 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -339,15 +339,4 @@ static struct i2c_driver wm8775_driver = {
.id_table = wm8775_id,
};
-static __init int init_wm8775(void)
-{
- return i2c_add_driver(&wm8775_driver);
-}
-
-static __exit void exit_wm8775(void)
-{
- i2c_del_driver(&wm8775_driver);
-}
-
-module_init(init_wm8775);
-module_exit(exit_wm8775);
+module_i2c_driver(wm8775_driver);
diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c
index e8a27844bf39..e86173bd1327 100644
--- a/drivers/media/video/zoran/zoran_device.c
+++ b/drivers/media/video/zoran/zoran_device.c
@@ -57,7 +57,7 @@
ZR36057_ISR_GIRQ1 | \
ZR36057_ISR_JPEGRepIRQ )
-static int lml33dpath; /* default = 0
+static bool lml33dpath; /* default = 0
* 1 will use digital path in capture
* mode instead of analog. It can be
* used for picture adjustments using
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index f6d26419445e..4c09ab781ec3 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -1958,7 +1958,6 @@ static int zoran_g_fbuf(struct file *file, void *__fh,
mutex_unlock(&zr->resource_lock);
fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
fb->fmt.field = V4L2_FIELD_INTERLACED;
- fb->flags = V4L2_FBUF_FLAG_OVERLAY;
fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
return 0;
diff --git a/drivers/media/video/zoran/zr36060.c b/drivers/media/video/zoran/zr36060.c
index 5e4f57cbf314..f08546fe2234 100644
--- a/drivers/media/video/zoran/zr36060.c
+++ b/drivers/media/video/zoran/zr36060.c
@@ -50,7 +50,7 @@
/* amount of chips attached via this driver */
static int zr36060_codecs;
-static int low_bitrate;
+static bool low_bitrate;
module_param(low_bitrate, bool, 0);
MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate");